I'm not quite understanding the difference between these two:
Num a -> Bool
Num * -> Bool
What exactly does the * indicate here? I'm also slightly confused about why numbers are of the type Num *
instead of Num
by default
In a vacuum, those two lines are equivalent
The second half of that type (whether it's *
or a
or apples
or Integer
) describes what kind of number (Num
) it is - it's like a type adjective
If it's lowercase or *
, it's a placeholder for a specific adjective like Integer
The lowercase letters/words are for referencing it and keeping track of matches, like this:
Num a, Num *, Num b -> { foo: Num b, bar: Num a }
The asterisk means it doesn't have to match any others in the signature
Got it :thumbs_up: thank you!
TLDR, the way to write "any kind of number" is Num x
, where x is *
or any identifier that starts with a lowercase letter
I think Int *
is a shorthand/alias for Num (Integer *)
, because there are subtypes of integers, too (I think size & signedness, like U8 vs. I128)
Adding new question about wildcard type to this stream, the tutorial says List *
is the type for the empty list []
so it make me think that a function with the type List * -> List *
would only accept and return an empty list. But the tutorial seem to imply that if List *
is the type of a function argument than it means a list of any type but if it is used for a return value then it means only the empty list. I find this confusing, why would List *
in one context mean an arbitrary list but the empty list in another context?
Additionally, when testing out in the repl, it says List.isEmpty
's type is List a -> Bool
instead of List * -> Bool
in the tutorial. Is the difference significant?
naming the type variable (so using a
instead of *
) can be helpful when there are multiple type variables at play
if I said to you: make me a list of an arbitrary type, how would you go about it?
the problem is: you don't know what the element type will be, so you cannot actually create any elements
hence the only list you can make, from scratch, that has an arbitrary element type, is the empty list
so in this way, the element list and "a list with elements of an arbitrary type" are related
but as you notice, they are not the same: in the input of a function, we can say we make no assumptions about the element type. This is what isEmpty
does: it does not matter what the element type is if all we want to do is see whether the list is empty
Folkert de Vries said:
naming the type variable (so using
a
instead of*
) can be helpful when there are multiple type variables at play
I see, that sort of make sense to me, my take away from your comment is that it's about describing what a type can be versus being able to construct a value satisfying the type which are two different things.
Last updated: Jul 06 2025 at 12:14 UTC