> 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.
Absolutely 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.
They go down and also allow for doing good AOT code generation to native code in the languages that have such toolchains, whereas dynamic languages really need a JIT.
After working on a startup that had a server architecture similar to AOL Server and also seeing some heavy Zope deployments (late 90's), I never got to understand the use of dynamic languages for large codebases.
It'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.
At 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.
Elm'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.
"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.
I 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.
> 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.
If 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.
I 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.
Having 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:
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:
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).
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.
[+] [-] spion|9 years ago|reply
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|9 years ago|reply
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.
[+] [-] pjmlp|9 years ago|reply
After working on a startup that had a server architecture similar to AOL Server and also seeing some heavy Zope deployments (late 90's), I never got to understand the use of dynamic languages for large codebases.
[+] [-] z1mm32m4n|9 years ago|reply
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.
[+] [-] ghayes|9 years ago|reply
[0] Basics: http://learnyouahaskell.com/types-and-typeclasses
[+] [-] catnaroek|9 years ago|reply
[+] [-] bootload|9 years ago|reply
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.
[+] [-] ralfd|9 years ago|reply
I think I am now officially feeling old. A language I never heard of is the introduction to programmers to static typing??
[+] [-] klibertp|9 years ago|reply
[+] [-] pka|9 years ago|reply
[+] [-] captainmuon|9 years ago|reply
[+] [-] moron4hire|9 years ago|reply
[+] [-] bo1024|9 years ago|reply
[+] [-] lucio|9 years ago|reply
[+] [-] dmix|9 years ago|reply
For example of a typical imperative approach to applying functions:
Compared to a haskell-style JS which combines currying and function composition (. combines functions in Haskell): Alternatively, you can easily create object specific total functions: 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).
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.
[+] [-] mrkgnao|9 years ago|reply
(I looked at the pics and saw `List.map` everywhere.)
[+] [-] ubertaco|9 years ago|reply
[+] [-] ndr|9 years ago|reply
[+] [-] warfangle|9 years ago|reply
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|9 years ago|reply
[+] [-] lucio|9 years ago|reply
http://debug.elm-lang.org/
[+] [-] iamcreasy|9 years ago|reply
Is this possible to do in imperative languages? i.e. in C++ or Java? If not, why?