9 ms·
Understanding the Elm type system
- mrkgnao 10y agoDoes Elm not have typeclasses? (I looked at the pics and saw `List.map` everywhere.)
- ghayes 10y agoAt first glance, Elm's type system looks like it borrows heavily from Haskell [0]. Learning Haskell's type system is a great mental exercise, even if you don't even up coding in the language. [0] Basics: http://learnyouahaskell.com/types-and-typeclasses http://learnyouahaskell.com/types-and-typeclasses
- catnaroek 10y agoElm's type system is a lot simpler than Haskell's. No higher kinds, no type classes, and certainly no crazy GHC extensions. OTOH, Elm has much nicer records, though Haskell sets the bar very low.
- elcapitan 10y agoIs Elm actually closer to Haskell or is it rather a typed Javascript in Haskell syntax? The documentation looks very accessible, there's a bit of introduction to the language, and then hands-on, that's nice. edit: by documentation I meant this gitbook: https://www.gitbook.com/book/evancz/an-introduction-to-elm/details https://www.gitbook.com/book/evancz/an-introduction-to-elm/d..., but the official documentation looks similar.
- catnaroek 10y agoElm has two things in common with JavaScript: strict evaluation and being designed for client-side Web development. In every other respect, Elm is closer to Haskell and diametrically opposite to JavaScript: (0) statically and strongly typed, with type inference (1) algebraic data types with pattern matching and exhaustiveness checking (2) purely functional
- elcapitan 10y agoThat's good to know. I wasn't sure if it's just a thin layer on top of javascript, or if it was stricter about this. Thanks! So the way it interacts with the dom seems to be similar to what I've read about React, in that it seems to always map the model to a view, rather than messing around with existing dom elements. That seems like something that is easy to understand and to reason about. The downside seems to be that it comes with quite a bit of js size, slightly larger than jQuery, if I understand it correctly.
- k__ 10y agoI think purescript is that. A thin layer on top ov JavaScript.
- fpoling 10y agoPureScript is a fully static strict functional language with a type system that is more advanced than that in Haskell as it allows to model all JS side-effects. It is based on the ideas for the type system in Koka [1]. That in turns allows more easily to integrate PureScript with JavaScript than Elm, but the language itself is anything but a thin layer over JavaScript. [1] - http://research.microsoft.com/en-us/projects/koka/ http://research.microsoft.com/en-us/projects/koka/
- k__ 10y agoInteresting :) When I was gathering information about typed languages that compile to JS, I found Elm rather nice, but calling JS libs was rather cumbersome. Somewhere I read that PureScript has a better integration with JS, so I thought it was a "thinner" layer :D
- bootload 10y ago"At first glance, Elm's type system looks like it borrows heavily from Haskell" I stumbled on Elm looking for a good language (Haskell) to build a new language. Try compiling Elm. hint: it's written in Haskell and if you squint, the type system is a simpler derivation of Haskell.
- z1mm32m4n 10y agoIt's refreshing to see a piece written by someone who's new to functional programming, discovering the beauty of types and pure functions for the first time. I very much agree with the author; learning functional programming idioms have had a profound impact on my ability to model problems in code, regardless of the language I'm using. I admire Elm so much for putting an emphasis on the user experience, recognizing that it has been one of the biggest blockers to making functional programming mainstream.
- spion 10y ago> For example, when writing an Elm program I might at some point decide that users should have an admin flag. I will then try to use that flag in a function at which point the compiler will tell me that I have failed to add it to the User model. I will add it to the model at which point the compiler will tell me that I have failed to account for it in my main update function. This beautifully explains why types are so useful. I don't know if the number of bugs goes down, but it sure is useful to have an assistant check all the implications of a change I want to make, and does that in a second.
- tommyd 10y agoAbsolutely agree, this is one of the biggest benefits I have found since I started working with Typescript (that, and the ease of refactoring). Of course Flow/Typescript's approach to typing isn't as complete as Elm's, but you can still gain some of the benefits by using one of them; and for many of us, introducing Flow/TS at work is a lot more likely to happen than introducing Elm.
- catnaroek 10y agoIronically, Elm's type system is actually one of the simplest out there. No subtyping (unions or intersections), no flow-sensitive typing, just plain first-order type constructors, Hindley-Milner type inference and nice records. Much of the complication in Flow and TypeScript's type systems comes from the need to accommodate existing JavaScript idioms.
- tommyd 10y agoGood point. I suppose what I meant was more that types are at the core of Elm and pervade every part of the language, whereas TS/Flow are adding types on top of a dynamic language and there are parts where it may be difficult or impossible to maintain type safety to the same degree (especially when interacting with non-TS/Flow code)
- catnaroek 10y ago
- ralfd 10y ago> Elm was my introduction to using a static, strong type system. I think I am now officially feeling old. A language I never heard of is the introduction to programmers to static typing??
- klibertp 10y agoI feel jealous instead. Being a bit old myself, I learned static typing from C and Pascal. It somewhat naturally led me to a conclusion that static type systems are these primitive, repetitive annotations which guarantee almost nothing while cluttering the code. It took me many years - and learning many languages - to recover from this perception.
- pka 10y agoWell, he said "strong" :) Probably meaning a ML-derived type system, not C's or Java's.
- catnaroek 10y agoWhy should anyone's first statically typed language be a weakly typed one in 2016?
- coldtea 10y agoBecause C and Java are still going strong and will continue to do so...
- klibertp 10y agoProbably because even in 2016 most programmers never heard of the other possible choices? I started with C instead of SML, which was available then, I think, because everyone I knew coded in C and they all said it's ok and a good language to learn. The same is probably true today: you first need to know that a language exists before trying to learn it, and beginner programmers are going to only know about languages their peers (other beginners, probably) use.
- steveklabnik 10y ago
- captainmuon 10y ago> A big gotcha for me was understanding the -> syntax. How can a function that accepts two arguments possibly have a type annotation like this? connectWords : String -> String -> String This is one of the most maddening things for me about Haskell-like languages. I can never remember if -> is left or right associative. I mean there is only one way that makes sense: # String -> (String -> String) But it could also be # (String -> String) -> String Of course you get used to it after a while, but a nagging feeling remains. I would really prefer a bit of syntactic sugar.
- moron4hire 10y agoIf you consider the case of currying and the fact that Haskell functions can be partially applied by just not providing all of the parameters, it becomes clear that only the first version you wrote is correct. It is a single-parameter function with a return type of another single-parameter function.
- bo1024 10y agoI think when these type annotations are used, at least traditionally in e.g. Haskell, the functions are curried by default. In other words, all functions only take one argument. If all functions only take one argument, then it has to be the first interpretation, not the second.
- Kiro 10y agoDoesn't String -> String -> String mean it takes two arguments in this case though? > The type annotation for connectWords is telling us that connectWords is a function that accepts two strings and returns a string. Or maybe I misunderstand this whole thing. I know nothing about Haskell/Elm.
- ncd 10y agoIt's a function that takes a String and returns a new function which takes a String and returns a String. All functions in Haskell/Elm are arity 1. So in order to construct functions that accept more than one argument, you actually return successive functions that apply successive arguments, known as currying.
- warfangle 10y agoAny suggestions on where to start with Elm? Learn You an Elm examples don't compile on the try-it-live console. Official examples do, but fail to compile on a local install (after setting up elm package install etc). Any suggestions on where to start troubleshooting? It's failing to find modules that are in the core standard lib.
- mml 10y agoI found many of the examples in the guides are now out of date since the recent release, which is very unfortunate.
- ocean3 10y agohttp://guide.elm-lang.org/ http://guide.elm-lang.org/ - contains examples that do work.
- warfangle 10y agoThey work in the live editor on elm-lang.org. But not locally. Maybe my environment isn't set up correctly? I tried the first one (the counter). Copy/pasted directly into a dir as 'counter.elm'. Initialized the dir with 'elm package install' to get the core library. $ elm make counter.elm I cannot find module 'Html'. Module 'Main' is trying to import it. Potential problems could be: * Misspelled the module name * Need to add a source directory or new dependency to elm-package.json Edit/update: source-directories is ["."] in elm-package.json. Dependency "elm-lang/core": "4.0.1 <= v < 5.0.0" is in elm-package.json. elm-version is "0.17.0 <= v < 0.18.0". elm-make is elm-make 0.17 (Elm Platform 0.17.0). core is installed in elm-stuff/packages: macbook:core me$ pwd /Users/me/elm-learning/elm-stuff/packages/elm-lang/core additionally, macbook:elm-learning me$ which elm /usr/local/bin/elm Edit2: so, I then guessed that Html wasn't a part of the core lib, and tried to install evancz/html, but apparently that doesn't work with 0.17 (I get an error about version constraints). I'm guessing the elm-lang.org editor doesn't use 0.17?
- 10y ago
- lucio 10y agoHonest question: How useful is that all functions are curried by default? Does this impose performance penalties?
- dmix 10y agoHaving curry by default allows you to create very readable code using function composition, which is the primary way of transforming data through multiple steps in FP. For example of a typical imperative approach to applying functions: function price(product) { product == 'book' && return 20 product == 'laptop' && return 10 } function addShipping(product, price) { product == 'book' && return price + 10 product == 'laptop' && return price + 5 } function addTax(price) { return price + (x * 0.13) } function total(product) { cost = price(product) subtotal = addShipping(product, cost) total = addTax(subtotal) return total } Compared to a haskell-style JS which combines currying and function composition (. combines functions in Haskell): price :: Product -> (Int) price p = p == 'book' && () => 10 p == 'laptop' && () => 20 shipping :: Product -> (Int -> Int) shipping p = p == 'book' && (x) => x + 10 p == 'laptop' && (x) => x + 25 tax :: Int -> Int tax x = x + (x * 0.13) total :: Product -> Int total p = tax . shipping(p) . price(p) Alternatively, you can easily create object specific total functions: totalBook = tax . shipping('book') . price('book') totalLaptop = tax . shipping('laptop') . price('laptop') Note how in the FP `total` version the data is not held in temporary variables but passed directly to the next function, which could be a performance gain. Another benefit is how it's easier to work with curried functions when using map/reduce and list comprehensions - two other fundamental building blocks of FP programs. For example, you can pass a curried `shipping` function directly to map whereas `addShipping` would required an anonymous function (since it has two arguments). map(shipping('laptop'), [5, 10, 20, 30]) vs map(function(price) { addShipping('laptop', price) }, [5, 10, 20, 30]) The performance question is largely a question of the implementation and compiler optimizations. But considering we're working in a browser environment the "bottle-neck" is going to be DOM interaction not passing around curried functions everywhere. Additionally, you are much more like to create functions in FP with single arguments rather than multiple in order for composition to work cleanly.
- lucio 10y agothe elm debugger seems also impressive http://debug.elm-lang.org/ http://debug.elm-lang.org/
- iamcreasy 10y agoWow! That's impressive. Is this possible to do in imperative languages? i.e. in C++ or Java? If not, why?