yes. There are also appendable and comparable and I think thatās all? All of these are special variable prefixes that also carry an explicit constrain. But by design are impossible to combine in elm. You canāt have appendable number. And all number are comparable otherwise you couldnāt use Set Int. Number is special because you can construct value that is number. You canāt construct value that is comparable. What you can construct is some concrete type of comparable but not a value of type comparable.
One thing to realize about these constrained type variables is that they donāt exist in type definition itself. Only in function implementation. This is legal:
type alias NoConstraintDict a b = Dict a b
but you wonāt be able to put any a in dict because functions to insert is where constraint applies. In reality these works like:
type Dict a b
insert : Comparable a => a -> b -> Dict a b -> Dict a b
the constrain is property of the function insert, not the dict type.
So here is an interesting program for you. It has Model number and it even does increment the number without knowing what type it is. What it canāt do is to display number. Because to convert it to String there is no function number -> String only Float -> String and Int -> String.
module Main exposing (main)
import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)
import Dict exposing (Dict)
type alias NoConstraintDict a b = Dict a b
type alias Model a =
{ count : a }
initialModel : Model number
initialModel =
{ count = 0 }
type Msg
= Increment
| Decrement
update : Msg -> Model number -> Model number
update msg model =
case msg of
Increment ->
{ model | count = model.count + 1 }
Decrement ->
{ model | count = model.count - 1 }
view : Model number -> Html Msg
view model =
div []
[ button [ onClick Increment ] [ text "+1" ]
, button [ onClick Decrement ] [ text "-1" ]
]
main : Program () (Model number) Msg
main =
Browser.sandbox
{ init = initialModel
, view = view
, update = update
}
Hopefully that gives you full idea about why I and some others keep bringing this discussion back from type variables to these constrained type variables. Especially the number because that one has literal which is constrained type variable you can construct (like 0, 0 + 1).
EDIT: Just realized we can stay in development build and use Debug.toString. So here you have Counter example in elm which is actually working with number, incrementing it and decrementing it while not knowing if itās Int or Float.
module Main exposing (main)
import Browser
import Dict exposing (Dict)
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)
type alias Model a =
{ count : a }
initialModel : Model number
initialModel =
{ count = 0 }
type Msg
= Increment
| Decrement
update : Msg -> Model number -> Model number
update msg model =
case msg of
Increment ->
{ model | count = model.count + 1 }
Decrement ->
{ model | count = model.count - 1 }
view : Model number -> Html Msg
view model =
div []
[ button [ onClick Increment ] [ text "+1" ]
, div [] [ text <| Debug.toString model.count ]
, button [ onClick Decrement ] [ text "-1" ]
]
main : Program () (Model number) Msg
main =
Browser.sandbox
{ init = initialModel
, view = view
, update = update
}
I think this is closest we get to āweird untyped programā. ellie