Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern matching: constants and rigid type variables

Tags:

haskell

A beginner's question.

I'm trying to understand how pattern matching works with constants.

-- myF :: [a] -> [a]
myF ('p':'r':'e':_) = "Prefix"
myF (x:xs) = x:xs
myF [] = []

This compiles and runs fine. However, if I uncomment the line that tries to specify the function's type, it fails with Couldn't match expected type a' with actual type Char' `a' is a rigid type variable bound by the type signature for: myF :: forall a. [a] -> [a]

https://godbolt.org/z/51oMGW4Ev

If I understand this error correctly, it complains that the function should work with any type, but the specialization for "pre" constant can only return String?

Does that mean that you can't "specialize" functions on constants of different types?

I.e.

myF ('p':'r':'e':_) = "Prefix"
myF (1:2:3:[]) = 0:[]

Again, not that this would be useful for anything, but just hoping to understand the pattern matching mechanism.

Thank you.

like image 465
Andy Venikov Avatar asked Dec 06 '25 07:12

Andy Venikov


1 Answers

Haskell is designed so that it is possible to run it without keeping type information at runtime (in the vast majority of cases). There are good reasons for that, one of which is optimization (less data to be kept and passed around).

That is, when we call a function

f :: [a] -> ...

f does not receive any information on the type a. Roughly, f is passed a bunch of "bits" that represent a list of something, but f does not know if the bits encoding the list elements are representing integers, characters, or anything else.

Indeed, it is possible (in theory, at least) that the list [0,1] has the exact bit-level representation as the list [False, True], so f can not distinguish between them. Coherently, we can't write

f [0,1] = [1,1,1]
f [x,y] = [x]  -- would match against [False, True]
...

The pattern matching rule is quite simple: we can only match against known types. So, we can match against Ints, (String, Bool), as so on. We can't match against a type variable like a since we don't know what that is. We can also partly match against [a] but no deeper than the list "level": we can match against x:y:z:[] since that only inspects the list, but x:True:[] would also match against a value of type a, so that's out.

Note that there are some advanced features of modern Haskell (like GADTs and Typeable) that can be used to keep some of type information at runtime, so that a similar form of the "forbidden f" seen above becomes possible. Since you wrote you are a beginner, I'd recommend you ignore these advanced features for now. Stick to the basics first, and once you are familiar with them you can then dig into the more complex features.

like image 56
chi Avatar answered Dec 08 '25 22:12

chi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!