O.K., here is an explanation:
When you define the data type:
type Schedule x =
Schedule x
{ today : Int
, maxItemsPerDay : Int
, schedule : Dict Int (Array x)
}
What exactly is defined here?
To look at it more closely, you can just write the name of the type in the elm REPL, and it will tell you what the type is:
> Schedule
<function>
: x -> { maxItemsPerDay : Int
, schedule : Dict.Dict Int (Array.Array x)
, today : Int
}
-> Repl.Schedule x
If we were to hide the body of the record for a short while to make it more apparent what is going on, it looks like this:
> Schedule
<function> : x -> {...stuff...} -> Repl.Schedule x
Woah! So Schedule
is a function that takes an element of type x
and a record of the proper format, and returns a Schedule x
.
So, Schedule
takes two arguments, the first one being the thing of type x
you want to store. And this is why the definition of empty
that you had creates a problem: The constructor to create a new element of type Schedule is not Schedule x
but rather Schedule
.
Elm sees you attempting to pass an x
as first argument to this constructor function, but note that we are not describing a type right now, but are in data land: There is no data variable (a ‘normal’ variable) called x
in this scope. You have used a type variable that happens to have the name x
in the function type signature, but the variable names you use in type-land and the names you use in data-land are completely unconnected. (Only in dependent languages like Idris might this sometimes be different).
And this is the case that the compiler complains that x
is not known in the definition of empty
.
Actually, there is no way to make empty
compile successfully for the type of Schedule
as you wrote it (other than using Debug.crash
which is not useful), because we cannot pluck an element of x
out of thin air: So either the constructor needs to change, letting us omit the x
, or you need to ask the user to pass in another variable. (Naming the variables in data land something else than those in type land can of course help to reduce confusion as well).
What @roovo thus wrote is probably (since I do not think that you wanted to add an x
to every Schedule) what you want.
So in summary:
- your confusion probably stems from the fact that the data constructor function is actually called
Schedule
and not Schedule x
.
- Even if things in type signatures and in function implementations might have the same name, they mean something different, and you cannot refer to a type variable from an implementation or the other way around, they are separate worlds.