Elm doesn't deduce type of Nothing value properly - type-inference

I have a following piece of Elm code (getProjectView function is omitted for brievity):
type Model = Maybe List Project
model : Model
model = Nothing
getView : Model -> Html any
getView model =
case model of
Just projects ->
ul [] (List.map getProjectView projects)
Nothing -> p [] [ text "Still loading..." ]
When I try to compile the following snippet, the compiler fails with the following error:
-- TYPE MISMATCH --------- E:\dev\irrelephant-code\client\elm\Views\Projects.elm
Tag `Maybe.Just` is causing problems in this pattern match.
32| Just projects ->
^^^^^^^^^^^^^
The pattern matches things of type:
Maybe a
But the values it will actually be trying to match are:
Model
Indicating that compiler can't deduce that this Nothing is a value of type Model (which in turn is an alias of type Maybe List Project).
What am I doing wrong here? Is there a way to explicitly mark this Nothing as a value of the Model type?
I am using elm v0.18.0

You want to define model as a type alias of Maybe (List Product). Right now, with the type keyword, you are defining a new union/tag type with one value, Maybe, which expects to arguments, of type List and Product.
A working example is https://ellie-app.com/3MhPcgGzXqRa1/0

Related

Trying to Understand this function and Im completely lost

I have been trying to understand the following function and I think i am interpreting it incorrectly. I am trying to convert it to Python3
type UITreeNodeChild
= UITreeNodeChild UITreeNode
unwrapUITreeNodeChild : UITreeNodeChild -> UITreeNode
unwrapUITreeNodeChild child =
case child of
UITreeNodeChild node ->
node
I see the bottom part is that there is a function called unwrapUITreeNodeChild which has a arg called child which is of UITreeNodeChild and the function returns a UITreeNode.
In Python i see it as:
class UITreeNodeChild(Enum):
UITreeNodeChild=UITreeNode
def unwrapUITreeNodeChild(child: UITreeNodeChild) -> UITreeNode:
if child is UITreeNodeChild: #
pass # I have no idea what it really means.
I dont understand the rest of the function signature. After looking at the ELM docs, i was confused as the switch but it looks like it is passing node into the definition of UITreeNodeChild.
I know im wrong here, but i would love to be both correct and proper explained to me.
EDIT
So it is looking for a typecheck essentially in the sample, so what you would want to do is confirm that it is that type and then use this new property in underlying code. It would look somewhat similar to:
class UITreeNodeChild:
pass
def unwrapUITreeNodeChild(child: UITreeNodeChild) -> UITreeNode:
if type(child) == UITreeNodeChild:
pass
Note you want to check type not check the exact same object.
You are looking at a tagged union and a simple pattern match against that tagged union.
In type UITreeNodeChild = UITreeNodeChild UITreeNode, the UITreeNodeChild on the right side is the tag. UITreeNode is the data type that is tagged.
When you say:
case child of
UITreeNodeChild node ->
node
You are pattern matching child against a pattern that begins with UITreeNodeChild. The tagged data type value is bound to the name node and this is also what it is returned from the case expression for this patten match.
Since this tagged union has only one variant you also have the option to unpack it in the parameter declaration:
unwrapUITreeNodeChild : UITreeNodeChild -> UITreeNode
unwrapUITreeNodeChild (UITreeNodeChild node) =
node
The way you do this in python depends on the way you chose to implement the tagged union. The general method is the same. You have to have some kind of tag and you have to have a way to determine the tag of a value. You can then return the embedded data type based on the tag. With a single tag this becomes just returning the embedded data type.

Scala doobie fragment with generic type parameter

I am trying to abstract inserting objects of different types into sql tables of similar structure. Here's what I'm trying to do:
class TableAccess[A : Meta](table: String) {
def insert(key: String, a: A): ConnectionIO[Unit] = {
(fr"insert into " ++ Fragment.const(table) ++ fr" values ($key, $a);").update.run.map(_ => ())
}
}
But I get this compile error:
[error] diverging implicit expansion for type doobie.util.param.Param[A]
[error] starting with method fromMeta in object Param
[error] (fr"insert into " ++ Fragment.const(table) ++ fr" values ($key, $a);").update.run.map(_ => ())
All I can find in the documentation is:
doobie allows you to interpolate values of any type (and options
thereof) with an Meta instance, which includes...
But it seems that is not enough in this case; what's the right typeclass/imports/conversions I need?
I'll go ahead an answer my own question, almost a year later. I never fully understood what was happening, and I have since updated to a newer version of doobie, so I am not sure how relevant this is. But now the documentation contains this clue:
Note: it is important to understand that Meta exists only to introduce
Get/Put pairs into implicit scope. You should never demand Meta as
evidence in user code: instead demand Get, Put, or both.
def foo[A: Meta](...) // don't do this
def foo[A: Get: Put](...) // ok
And indeed, between that change and the new version, this now compiles just fine for me:
class TableAccess[A: Get: Put](table: String) {
When the compiler is resolving implicit its searches for one of a specific type in the current scope. Here it seems like his finding more than one in his tree search.
It's not a matter of a missing typeclass or imports, it's more like you have too many of them and the compiler cant figure the right one.
Try removing some implicit and see how that works or pass them explicitly.
One way I resolved this was to localize the type parameters (and their evidence) onto the method (on a static/companion object), and then it compiled.
Something like
object MinimalGood {
def good[A: Meta, B: Meta](a: A, b: B): Update0 =
sql"""$a $b""".update
}

what does the elm signature mean in "Program Never Model Msg"?

I'm just starting on elm and without understanding Haskell and its compiler
I'm trying to grasp what the signature mean in Html.program
func: (a -> String) -> String -- this means expects a function and return a string
main: Program Never Model Msg -- What does this mean?
Program is a type parameterized by three type variables: flags, model, and msg. Never is a type that cannot have any value (see the link for a good explanation of what this means and how it differs from the unit type ()).
Program Never Model Msg therefore is the type of a program that doesn't have any flags (Never), has a model of type Model, and passes messages of type Msg.

Elm Language What do the Multiple Types in a row (without the arrow) in a signature mean?

In the Elm language, I'm having a hard time explaining my question...
In these snippets in elm:
I understand the signature in something like
update : Msg -> Model -> Model
where the parameters / output is separated by arrows, but how do I read / grok things like:
Sub Msg
Program Never Model Msg
In:
main : Program Never Model Msg
main =
program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
In a type signature, parameter types are separated by ->, with the last type being the return value.
If there are no -> symbols, then it means it is a value of that type. In your main example, the type of main is Program Never Model Msg. It has no arrows, so it takes no parameters.
Now, each parameter and the return value in the type annotation may have several things separated by spaces, as in your main example. The leftmost is the type, followed by type parameters separated by spaces.
Program Never Model Msg
| | | |
| ------|-----
type type parameters
A type parameter is similar to Generics in a language like C#. The equivalent syntax in C# would be:
void Program<Never, Model, Msg>()
C# doesn't directly correlate because it has a different way of constraining generic type parameters, but the general idea holds.
The Elm guide doesn't currently have a great deal of info, but here is the section talking about types.
Sub Msg, List Int, Program Never Model Msg
Sub, List and Program are type constructors. You can think about them as functions that take a type and return another type.
By themselves, Sub, List and Program are not complete type. They are like a puzzle missing a piece. When one adds the missing piece, the puzzle is complete.
I usually read them in my head using the word of as in a List of Ints, a Program of Never, Model and Msg.

Infinity symbol in Elm

In a project I'm working on with a colleague, we are usign the UrlParser module and we stumbled in this error:
The type annotation for ourParser does not match its definition.
The type annotation is saying:
UrlParser.Parser a a
But I am inferring that the definition has this type:
UrlParser.Parser (String -> ∞) (String -> ∞)
Hint: A type annotation is too generic. You can probably just switch
to the type I inferred. These issues can be subtle though, so read
more about it.
Our code is something like
ourParser : UrlParser.Parser a a
ourParser =
UrlParser.oneOf
[ UrlParser.s "home"
, UrlParser.s "detail" </> UrlParser.string
]
The main question is: what is this ∞ symbol? Where is it defined? If I try to copy/paste it in my function definition I get a syntax error, as if Elm actually doesn't know what that character is...
The following question is: how such an error happens with my code?
The second parser in your list of alternatives combines
UrlParser.s "detail" : Parser a a
UrlParser.string : Parser (String -> b) b
using
(</>) : Parser u v -> Parser v w -> Parser u w
As you can hopefully see, the following types must match up:
u ~ a
v ~ a
v ~ (String -> b)
w ~ b
The resulting type is
UrlParser.s "detail" </> UrlParser.string : Parser (String -> b) b
The first parser in your list of alternatives has type
UrlParser.s "home" : Parser c c
Because you're building a list of these, they must have the same general type. As such, c ~ (String -> b), but also c ~ b. What you have here is a loop, resulting in an infinite type. That is what the infinity symbol means.
The error text is indeed misleading, because infinite types are not supported in Elm's type system (because they make no sense). This sounds like a bug, as Elm should explain that infinite types always point to a programming mistake.
The documentation for oneOf shows how parsers of different types could be combined through the use of format.
In any case, you need to turn your first parser into something of the type Parser (String -> c) c. From the types, it looks like applying format "some string" to the first parser would already suffice, but I don't know enough about Elm or the UrlParser to give any guarantees about that.