Please share your knowledge of any lesser known Elm syntax that is not mentioned in the official overview (http://elm-lang.org/docs/syntax) and is possibly buried somewhere else and easy to miss.
I was pleased to find out that for function parameters that are records or tuples, you do not need to choose between either destructuring that parameter OR giving a name to it as a whole. You can do both at the same time using the wrapping (… as foo) syntax!
Has anyone described the rules for infix symbols available for function names? I know this is discouraged in practice, but nevertheless, it’s interesting
Record types can contain a type variable to say “I don’t care what else is in this record as long as these fields are”. It’s really useful for passing your model to your view function, but using the type system to show that the view doesn’t rely on most of the fields, and it lets you fuzz smaller inputs.
Example:
distance : { a | x : Float, y : Float } -> { b | x : Float, y : Float } -> Float
distance p1 p2 = ...
dist = distance {x=2, y=3} {x=4, y=5, z=6}
By using different type variables, we say that the other fields in the two records don’t need to be the same. That allows us to pass two different types and get a sensible answer out.
(Unfortunately, there’s not a way to take either 2D or 3D coordinates and default aTwoDimensionalPoint.z to zero. Define your 3D type and then have a function that takes two arguments and fill in the zero.)
Yes, you will get an error about ambiguity, but only if you try to use such values. But in this case you can always refactor so it’s safe!
Moreover, it’s even possible to import a module more than one time with different names:
import List.Extra
import List.Extra as List
Now you can use List.Extra when there is an ambiguity and just List in other cases. Although it’s probably not worth it since it will make the code less clear (also elm-format doesn’t allow this).
This actually doesn’t sound like a desirable behavior, as it would force anyone unfamiliar with either module to search through both to find details about an unfamiliar function call.
Yes. For a language and community that generally seems to value being explicit, having a mechanism that slams two modules together seems to cut against that. Of course, so does using (..) in imports which slams everything into the module namespace, so maybe this is just more of the same.
There’s probably something for you here, if you want to understand why it works this way from a design perspective - rhetoric aside, it also seems like undesireable behavior from my perspective.
This sounds like something I would find useful, but as a beginner I’m struggling to appreciate the detail. Are you able to expand on this at all, please?
A word of warning, as a beginner I really overused extensible records and got myself into some painful situations. In particular, don’t try to replicate an object-oriented-style inheritance system with them
I’ve found them most useful in function signatures rather than as part of my models:
-- THIS
filterByName : String -> List { name : String } -> List { name : String }
filterByName name items =
List.filter (\item -> item.name == name) items
-- NOT THIS
type alias Nameable a = { a | name : String }
type alias User = Nameable { age : Int }
type alias Building = Nameable { address : String }