I'm having some trouble understanding what exactly the Html msg type is, or how it gets used. I found this line of code in VirtualDom.elm, which Html msg seems to be an alias of:
type Node msg = Node
This looks like a generic union type with one type parameter, msg, and one trivial case that holds no additional information. I'm wondering:
How does the div function construct one of these objects?
How does an object like this get used?
How could an object like this get used?
Is there any value for a user to define a type like this, or is Html msg just a magical type to support the Elm compiler/runtime?
Html msg is a Type Alias for Node msg, which is a Generic Union Type
Union Type Node msg
It only makes sense to reason about Node msg type signature in a context of Elm Architecture, where all input for your application, except flags for Http.App.programWithFlags, is happening through messages.
msg type variable in Node msg is only hinting you towards the idea, that all messages from your DOM sub-tree should belong to a single union type.
node
: String
-> List (Attribute msg)
-> List (Html msg) -- List of children nodes with a msg
-> Html msg -- Produced DOM node
How div function uses generic Union Types
Thanks to msg type variable, Elm compiler knows, when your DOM tree is correct in the context of Elm Architecture.
In JavaScript world Node value of Node msg Union Type is representing the object with the following structure:
{
"type":"node",
"tag":"div",
"facts":{}, // Attributes and DOM events
"children":[], // Children, have the same structure
"descendantsCount": 0 // Used for Virtual DOM diffing
}
How you can use generic Union Types
Most of the complex core data structures are implemented using generic Union Types, check Maybe or Dict to get inspired.
Html msg and user-defined generic Union Types
Html msg in particular is somewhat magical, but you can implement some interesting structures, like linked lists or other tree-like structures.
type List a =
Empty | Node a (List a)
Related
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.
Can Elm Html have Bool type variable so instead of type annotation of
Html Msg
have
Html Bool
Does anybody knows? Thanks a lot to all.
Yes. Elm Html uses the type Html msg (with a small caps msg). This means that msg can be whatever type.
In many code examples found online, msg is Msg. But that is just their choice, and they have defined Msg themselves somewhere else in the code.
In your code you can use any other type, like Bool.
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
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.
Just taking a peek at elm code and came across the following type definition:
type Cmd msg = Cmd
I just can't seem to understand how this works. Anybody can explain?
That isn't a recursive type definition, it's defining a type Cmd as a union type with one label, Cmd, which contains no extra information. Usually definitions like this are intended to signal that the type represents values that have no individual meaning in elm.
In this case, the type is defined that way because all operations on Cmd are hidden in platform code, so there's no need for users to be able to examine or destructure Cmd values. Cmd needs to expose a type variable in order to preserve the type safety of Cmd values, because they encapsulate a promise to yield a message of a given type and that type can be be changed via Cmd.map .