Hacker News new | past | comments | ask | show | jobs | submit login
What I Wish I Knew When Learning Haskell (stephendiehl.com)
306 points by gtani on April 14, 2013 | hide | past | favorite | 99 comments



I think these 3 slides really stand out, they show with how little code one can write serious software in Haskell...

1. ACID (acid-compliant persistance on Haskell data types, with indexes)

http://dev.stephendiehl.com/hask/#(27)

2. Pipes (program on streams of data)

http://dev.stephendiehl.com/hask/#(30)

3. Scotty (micro web-framework, a la Sinatra or Flask, on top of the super fast Warp server) http://dev.stephendiehl.com/hask/#(32)


About your point 3), it's worth noting the "toHtml" call buried in that example.

Haskell is both strongly and statically typed. That type boundary between strings and HTML output is enforced by the compiler, and it automatically (and provably!) prevents a metric crapload of injection attacks.


To bring this into sharper detail, notice that there's the "OverloadedStrings" compiler directive at the top of the file. That means that "hello " and "!" are of type Html, different from String. Strings can only be concatenated with Html after they've been escaped.

For more elaboration, see http://blog.moertel.com/posts/2006-10-18-a-type-based-soluti...


Here's an example that brings together Aeson, Lens, Acid-State and Scotty together in one file. Haskell really does have some great offerings for building very solid and fast web applications.

[1] https://github.com/sdiehl/haskell-warp-rest/blob/master/serv...



Can acid-state be ported to Javascript?


Maybe but it does not seem very obvious to do so to me.. I guess one is better off with using JS's localStorage from Fay[1] or Sunroof[2].

1. http://fay-lang.org

2. https://github.com/ku-fpg/sunroof-compiler/wiki/Tutorial


you could try cross-compiling it with Fay or UHC (haskell to javascript compilers)


You'd probably need one of the more heavyweight options (e.g. GHCJS). Fay doesn't understand typeclasses afaik, so it's not really suitable for porting haskell libraries verbatim to the browser.


I disagree completely with his analysis on monads.

If you just present the abstract structure, you cannot understand why you even want (for example) the do notation as a language-level concept. I think this is more of a case of bad examples than anything.

Trying to represnent monads via analogy works badly too though, because monads as used in haskell are more about programming pragmatics than modelling real world objects.

The way to explain it should be :

- Show real code

- Explain why we use this structure to write our code .I think a good explanation is to ...

in Jquery you do things like chaining to build things.

$('selector').css('color','red').filter(someFilter).css('color','blue')

Chaining APIs are useful because you're combining computation('chaining'), and you don't want to have to carry around a value everywhere. You want to do the same thing in Haskell obviously.

Haskell doesn't have dot notation, so you can't do this style exactly. First idea would be to do something like

let x=jQuery document selector in let y=css x 'color' 'red' in let z=filter y someFilter in ...

This is a pain, especially considering that the 'chaining' here is mechanically obvious

let [n+1] = f [n] [whatever] in let [n+2] = g [n+1] ....

So monads, in the most pragmatic sense, allow you to represnt this form of computation. You end up with

jQuery 'selector' >>= css 'color' 'red' >>= filter someSelector >>= css 'color' blue'

You implicitly carry around your computation.

)

In any case the Maybe monad is the worst example ever, just like how a singleton group is a bad example. Sure it's the 'simplest' , but it's far from the most typical


I'm not sure you actually disagree with his method of learning monads.

He primarily advocates for avoiding the use of analogies, which you seem to agree with. He advocates using concrete monads in real code, which you also seem to agree with.

The only contentious point might be learning typeclasses and how monads fit into the Typeclassopedia. If you want to be able to trace how your monad-using code is evaluated this is a necessity. Like it or not. Also, attacking monads from both the concrete and the abstract at the same time seems to be a good approach, with satori being achieved once the understandings meet. A dynamic-programming approach?

You may possibly be disagreeing with the order in which he lists these components of learning in his 'Eightfold Path', but if the analogy to the Buddhist teachings is followed further, then the steps need not be taken in sequence.

The slides certainly include many monad examples besides maybe at any rate.

I think the slides are worth another look :)


The problem with bringing jQuery into the discussion is that it's not a monad. Don Stewart explains this more elegantly than I can [1] but the crux of the argument is that chaining together computations is not enough to be a monad, one needs to prove that the monad laws hold.

[1] http://stackoverflow.com/questions/10496932/is-jquery-a-mona...


The majority of the 'proofs' I've seen that jQuery isn't a monad seem to either be probabalistic, or use the "Burden of Proof" argument to show that since nobody has proved that jQuery is a monad, we should assume that it isn't. I agree that jQuery probably isn't a monad, but it rubs me the wrong way that people aren't willing to say "It has yet to be determined if jQuery is a monad".

Obviously it is trivial to show that it isn't a monad by the fact that javascript permits any action in pure code, but by the same token, unsafePerformIO proves that Haskell has no monads. I think it's fair to operate under a reasonable subset of jQuery functionality when asking the question.


The point is that the concept of monad is a very concrete thing. Monad is not "chaining operations". Monad is not "returning actions instead of values". Monad is not some vague concept.

If JQuery is a monad, what are the monadic operations that make it a monad? What are its equivalents of return and bind (or any other equivalent definitions of a monad)? It's not a tricky question.

Saying that JQuery is a monad without saying what its return and bind are is equivalent to saying that whistling is Turing complete without saying how you can compute stuff with whistling. The problem here is not whether whistling is Turing complete or not, the problem is what it would even mean for whistling to be Turing complete.

This means that as of now, as long as you don't tell us what are the monadic operations of JQuery, it cannot be determined whether JQuery is a monad, because this question does not make sense yet.


JQuery is an implementation of the List monad.


JQuery is an enormous API, so it is implausible that it is an implementation of the list monad. Some aspect of it might be the list monad. If so, which?


Most jQuery methods are functions that are mapped over a collection of elements. Many verbs return collections themselves, which are concatted together into the resulting collection. That's analogous to how List works.

So $(element) implements return as a -> [a]

And bind is mapcat, which is called by most of the jQuery methods.

Yes, that's a subset of the API, but it's the subset that distinguishes jQuery from any other collection of helper functions.


$(element) does not implement return. $($(element)) gives $(element), which means that it does not work on an arbitrary datatype, which means that it does not implement return.

jQuery may be analogous to a monad. That doesn't make it a monad.


There's a lot of stuff in jQuery that's not monadic, but that doesn't disqualify it. There's no law that return(return(x)) has to be defined - a Haskell List of Integers is still monadic, even though return(return(1)) would be a type violation. And undefined code can do whatever you want and not be a problem for the definition.


No, I'm sorry, you're wrong. return(return(1))::[[Int]] gives you [[1]]. For something to be a monad, it must be a polymorphic type of kind * -> * . That means it must be a type constructor which takes any type as a parameter. Any type, including a concrete type constructed from the type constructor you are declaring an instance of Monad.


No, a monad is not something that implements the Haskell typeclass Monad. A monad is anything that satisfies the monadic laws - and they don't say anything about polymorphism, only associativity and left/right identity. I assert that you can implement a structure that satisfies those laws without having return(return(x)).

Can you disprove that?

(P.S. you are wronger)


Yes, I can disprove. This has nothing to do with Haskell, I'm only going to use the monad laws. The first monad law says:

    bind f (return a) = f a
For all a and f. Therefore, by substituting f = id, and a = return x:

    bind id (return (return x)) = return x
If, as in jQuery, `return (return x) = return x`, then we can simplify to:

    bind id (return x) = return x
Now, applying the first monad law again, we get:

    x = return x
So return must be the identity function. But jQuery's $ is not the identity function. Contradiction. QED.


I like your answer, but I'm going to refuse to concede that it's correct, out of stubbornness.

No wait, I can do better. For some values, $($(x)) is the equivalent to $(x). So, for some values $(y) = y. So for the domain of y where $(y) = y, $() is the identity function, and now it's a monad.


Now it's a monad how? What category is it a monad on, and in what way does it satisfy the monad laws? Are you really saying that sometimes $() is return and other times it's id, and presto magico it's a monad?


Look, if you want to have a discussion with a reasonable person who's going to try to follow your arguments and retort them under the exact same level of rigid discourse that you are using, maybe you should try someone other than me.

But yes, presto magico. I am outwitting your narrow-minded mathematics.


Well, as long as it's all in good fun :-)


In that particular reply I was talking Haskell specifically; I should have been more clear. You are of course right that being a monad does not mean being an instance of the Haskell type class Monad. It means being a monoid in the category of endofunctors. It does not mean "anything that satisfies ... associativity and left/right identity". You have to specify what operation is associative, which in this case is composition of endofunctors. Associativity and identity on binary operations on sets, for example, gives you a monoid, but not a monad.

Monads are more specific, and it is in that specificity that you find the requirement for monads to be "polymorphic": monads are endofunctors, and the monad laws concern the composition of those endofunctors. An endofunctor is a mapping between a category and itself. When we apply this category theory to programming, we talk about a category of types. In Haskell this is the category Hask. This is where the polymorphism requirement comes into play. The monad maps from Hask to itself. That means that it must be able to map over all types, which means polymorphism.


nah, I still don't buy it. Mapping Hask to Hask is an arbitrary choice.


The part that isn't arbitrary is that monads are endofunctors, meaning they must go from a category to itself. That means that the domain and codomain are the same, which means that you must be able to wrap already-wrapped values. There's no way around that.


Agreed.


A monad must have a `return` function that works on an arbitrary datatype. That includes a datatype that is already 'wrapped' in the monad. For example, `return $ Just 5` yielding `Just (Just 5)`. jQuery does not have such a function. The `jQuery` function can 'wrap' strings, but it cannot wrap, for example, other jQuery objects. If you try, you simply get the original jQuery object back. Accordingly jQuery does not satisfy the monad laws, and is therefore not a monad.


I deny that the return function is required to act on arbitrary data types. In Haskell, is the type [Integer] no longer a monad because it only can contain integers?


The distinction is:

return [Integer] will give you [[Integer]] (if you're inside the list Monad).

$($("#some-id")) will give you the same result as $("#some-id"), because $ of a $ doesn't nest (or make sense, really).

Therefore jQuery doesn't satisfy the Monad laws :).


Yes, in Haskell the type [Integer] is not a monad. For a type to be an instance of the Monad type class, it must be of kind * -> * . As [Integer] is of kind * , it cannot possibly be an instance of Monad.


I didn't mean to suggest that [Integer] was of type Monad, I meant that when you write code in terms of the List monad, that code still works and is still valid and is still "monadic" even when the input to that code is a list of a non-polymorphic type.


I really don't follow what you're trying to say here. >>= has signature m a -> (a -> m b) -> m b, so clearly you are working with a concrete type m a. The point is that the concrete type isn't what instantiates the Monad type class, the constructor m is.


well how'd we define

   return :: a -> m a
in the jQuery monad?

First I thought

   return = jQuery
but

    $(".yo") :: [HTMLElement]
isnt

    return ".yo"   :: JQuery String

I'd probably model it like this:

    (|>) = flip ($)

    jQuery "selector" |> css "color" "red" |> filter someSelector |> css "color" "blue"
which would turn into:

    css "color" "blue" (filter someSelector (css "color "red" (jQuery "selector")))


    class Selector a where
    instance Selector Text where
    instance Selector HtmlElement where

    jQuery :: Selector a -> JQuery
    css :: Text -> Text -> JQuery -> JQuery
    filter :: Selector a -> JQuery -> JQuery


Notwithstanding the critics, I've read many explanations of Monads, and I found this one helpful, especially coming off of Eric Lippert's:

http://stackoverflow.com/a/2704795/4525

I get it now, so thanks!


Maybe is not the simplest monad, Identity is, and I think Maybe is an excellent example of a monad.


Identity is simpler, but it's not very interesting. It's hard for a beginner to see why you would ever use the Identity monad.

Maybe is the simplest interesting monad, which makes it a good candidate for explaining monads to beginners.


Your pipeline example looks more fit for simple function composition.

  f = filter (\x color x == BlueColor) . select (\x color x == RedColor)


That's true for this example, but when you do tree walking stuff in jQuery (like elements.children().children() ) then you have to think of it as a concatting map instead as just a regular map or filter


I've read lots of monad tutorials. I get it, they're a way of encapsulating side-effects in a pure lazy language.

But Haskell doesn't sink in unless I use on a regular basis. The time that I've felt like I was able to see a light at the end of the tunnel (i.e., that I might be able to be useful enough in Haskell that I could keep using it regularly) was when I simply memorized the expansions for the do, <-, return sugars.


You've just proved that the monad tutorials you've read are useless. Monads are emphatically not "a way of encapsulating side-effects in a pure lazy language". Haskell's IO type is a way of encapsulating side effects in a pure lazy language. Haskell's IO type happens to form a monad. The fact that it forms a monad is completely irrelevant to what it actually does.

Forming a monad is a very abstract consideration. It has to do with the data type supporting a couple operations with specific properties. It doesn't say a thing about what those operations mean, so long as the required properties hold. It's up to specific monads to insert semantics into those operations.

And so yes, the IO type specifies that its monad operations mean "creating a trivial IO action that gives a specific value when executed" and "feed the result of executing an IO action into a function that returns another action." And that turns out to be a sufficient framework for composing IO actions together, once something else is providing them.

But IO isn't the only monad. There are hundreds of others already defined, and an unlimited number that can be created. What matters is that they can implement a couple functions with the required properties.

So I've said monads are abstract. What's the point then? Well, put simply, a language with the kinds of primitives Haskell has can actually put the abstraction into its libraries. This allows writing code that works at the level of the abstraction, rather than any specific implementation. The monad abstraction turns out to be rich enough to implement all kinds of conditionals, loops and recursion structures, function application patterns, etc.

In fact, work with parser combinator libraries has shown that the monad abstraction is the simplest one that allows you to express any context-sensitive grammar. If you've ever studied automata theory, bells should be ringing about now. The monad abstraction is sufficiently rich to express Turing-complete operations over the kinds of types it applies to.

And that's the real point. The monad interface allows you to specify those kinds of operations generically. Once they've been written, you can apply them to any type that provides the interface (correctly).

The fact that there's an IO type that happens to provide the interface is an accident that's only relevant historically. The benefit is much larger than that.

This kind of comes down to Rich Hickey's "simple vs easy" point. Monads are incredibly simple, but they're not easy for people who aren't used to looking for deep abstractions. One of the insights made in Haskell library design is that category theory contains several ideas that are incredibly simple and powerful as abstractions for software creation. Monad is hardly the only one - it's just the only one getting press.


I know that the IO type and monads live at different levels of abstraction. I am interested in the stuff that you were saying about automata theory. But I'm not as smart or have as much time and energy as that lady from Taiwan who implemented the Perl 6 in Haskell parser combinators.

In order for me to use Haskell, I need to be able to get fluent enough with it that I can be productive munging data with it. This means IO, it means a database library, regexes, and manipulating binary data.

For example, I tried to do a program that would do some HTTP stuff. The HTTP was in the IO monad, but the database connection was in a different monad. So now I'm looking into monad transformers http://book.realworldhaskell.org/read/monad-transformers.htm... (chapter 18) and my head asplodes.

I love Haskell, but it's one of the few things I've found to consistently make me feel stupid.


I'd ask, if you know that IO and monads are different, why your first statement was conflating the purpose of IO with the purpose of the monad interface? If I just totally missed a joke - ok, my mistake. But if you really don't see why it matters that the statement is false, I recommend really thinking about it for a bit.

Now, on to the thing about Haskell that the endless proliferation of monad tutorials obscures.. You don't actually need to "understand" monads to use it. You can get by on type signatures and the most basic parts of do notation for a long time.

In fact, that's what I did. I spent months working on haskell code, understanding the transformations I was making, but not understanding the abstractions beneath them. The first time I really grasped the purpose of the monad interface was when I decided to learn how to use the parsec library. I was a bit unsure how to combine smaller parsers into more complex ones, but just sort of tried do notation - and it worked. It worked exactly how I expected it to. And that's when I realized you could see the monad interface as "The thing you need to make do notation work like you'd expect." Even if I was still fuzzy on the details.

But before that, I was making use of monad transformers. I did a poll in the #haskell IRC channel once. Almost everyone agreed monad transformers are easier to learn about than monads. There's just one simple type signature involved, and it's easy to just fit the pieces together, without a deep understanding of what they mean. They end up doing what you expect, anyway.

You really can use haskell productively without understanding the underlying abstractions, so long as you are good at following the types. They're there to help you - they do the job pretty well, if you take a bit of time to learn how to apply them.


> if you know that IO and monads are different, why your first statement was conflating the purpose of IO with the purpose of the monad interface?

Just for brevity. Everyone knew what I was talking about. I'm sorry. I don't like that I was imprecise and confounded monads with the IO type any more than you do.

Considering that monads in Haskell were discovered as a solution to the unweildy problem of performing I/O in a pure functional language, and that all of the early tutorials approach them from that direction, don't you think it's a teeny bit disingenuous to suddenly act like they are completely unrelated and orthogonal concepts?

Maybe I should take another crack at Haskell. But I'd just started Erlang and Riak...


It's true that the abstraction got attention when they realized it solved the IO problem. (Before the IO type, IO in Haskell was painful.) It's quite possible it wouldn't have become a significant part of the ecosystem without the fact that it solved the IO problem neatly.

But solving the IO problem neatly is a consequence of the value of the abstraction. It solves it so well because of its useful properties.

I'd say you should take another crack at haskell sometime. But if you're learning Erlang now, stick with that for the time being. It's also got plenty to teach.


Monads were originally introduced by Wadler in his Monads for functional programming paper. In it he mentions state and I/O but also exception handling, parsing and non determinism.


Of course you're correct in the literal sense. But reading things like "The History of Haskell: Being Lazy with Class" Hudak, Hughes, Peyton-Jones, Wadler gave me a different perception.

The first time the term monad is mentioned, it is in the description of the agenda of the paper: "monads and input/output (Section 7)".

The second time is "May 1996. ... Monadic I/O made its first appearance, including “do” syntax (Section 7), and the I/O semantics in the Appendix was dropped."

A few more occurrences of the term and we get to section 3.2 "Haskell is pure" which says "Necessity being the mother of invention, this embarrassment ultimately led to the invention of monadic I/O, which we now regard as one of Haskell’s main contributions to the world, as we discuss in more detail in Section 7."

"Section 3.8 Haskell and Miranda ... More fundamentally, Haskell did not adopt Miranda’s abstract data types, using the module system instead (Section 5.3); added monadic I/O (Section 7.2); and incorporated many innovations to the core Hindley-Milner type system, especially type classes (Section 6)."

"Section 6.4 Higher-kinded polymorphism The first major, unanticipated development in the type-class story came when Mark Jones, then at Yale, suggested parameterising a class over a type constructor instead of over a type, an idea he called constructor classes (Jones, 1993). The most immediate and persuasive application of this idea was to monads ... Jones’s paper appeared in 1993, the same year that monads became popular for I/O (Section 7). The fact that type classes so directly supported monads made monads far more accessible and popular; and dually, the usefulness of monadic I/O ensured the adoption of higher-kinded polymorphism"

The entire Section 7 is called "Monads and input/output"

Section 7.3 "Monadic I/O Although Wadler’s development of Moggi’s ideas was not directed towards the question of input/output, he and others at Glasgow soon realised that monads provided an ideal framework for I/O"

As a Haskell novice I think I could be forgiven for having the perception that the evolution of monads in Haskell was driven by the unwieldyness of managing mutable state (such as I/O) in a pure lazy language.

https://research.microsoft.com/en-us/um/people/simonpj/paper...


Yea, I'm not blaming anybody. Just pointing out that it was recognized that monads were useful beyond I/O in the early days. It's definitely true that I/O was a major impetus for them.


>as that lady from Taiwan who implemented the Perl 6 in Haskell parser combinators

That would be Audrey Tang. The Perl6 on Haskell project is called Pugs.

* http://en.wikipedia.org/wiki/Audrey_Tang

* https://news.ycombinator.com/user?id=audreyt

* http://en.wikipedia.org/wiki/Pugs

* http://www.pugscode.org


I'm going to give a mini monad tutorial here. Hopefully that will also clear up at least some of the confusion in the other threads here.

A monad is a container type with at least these three operations:

1. unit(x): Create a container with a single element x inside.

2. map(f,c): Given a container c with elements, call the function f on each element, and create a new container out of the results.

3. flatten(c): Given a container of containers, we can flatten it down by putting all the elements in the nested containers in a single container.

For example, a List<T> is a monad:

1. unit(x) creates a list with a single element.

2. map(f,list) calls f on each element of the list, and creates a new list out of the results.

3. flatten(listoflists) flattens the nested lists down. Note that flatten only flattens away one level, so if you have a list of lists of lists, then flattening it will get you a list of lists.

These operations have to have some laws, like:

1. map(f, unit(x)) = unit (f x): if we map a function over a container with a single element, we just call the function on that single element and put it inside its own container.

2. flatten(unit(c)) = c: if we wrap a container c in its own single element container unit(c) then flattening it gives us back the original.

3. flatten(map(unit,c)) = c: if we take each element of a container and wrap each one in its own container, and then flatten the result, we get back the original.

Turns out that you can also define these operations for sets and multisets. The interesting thing is that there are more things that fit in the API above. Futures, parsers, probability distributions, I/O operations, mutable state, dynamic scoping, exceptions, optional values, logic programming, continuations, asynchronous programming, and more. Monads are what all those things have in common. I think the only way, ultimately, to learn how monads work is to study many examples. You may ask yourself, for example, what does it mean to flatten a parser? Turns out you can give a meaningful definition for flattening a parser. If you study many such examples, you start to get the pattern.

What makes monads so neat to use is that you can define special syntax for it. For example list comprehensions can be translated to the operations above, which means that list comprehensions also work on all the other things that are monads. So you get "parser comprehensions" and "futures comprehensions". Similarly, mutable state has special concise syntax in imperative languages, but with monads that syntax also works for lists, probability distributions, etc. That's what do-notation is in Haskell.

I hope this helps somebody get interested in what monads really are about.

That said, to use I/O in Haskell you do not need to understand any of this. If you can read this:

    do print "What's your name?"
       name <- readLn
       print ("Hello, " ++ name)
Then you're good to go. You do not need to know that there is a I/O monad underneath this, you can just do like you're coding in an imperative language. The only difference is that the syntax above is not restricted to I/O and mutable state like it is in most languages, but it can also be used for creating parsers, manipulating lists, etc.

For example, the assignment operator in the I/O monad means assignment, but in the list monad it means "take each element of":

    do x <- [1,2,3]
       y <- [4,5,6]
       return (x*y)
This creates the list

    [1*4,1*5,1*6, 2*4,2*5,2*6, 3*4,3*5,3*6].


> Haskell, I need to be able to get fluent enough with it that I can be productive munging data with it. This means [...] regexes

It's possible to use combinator parsers (e.g. Parsec) to do everything regexes can do (plus the extras), although regexes are available if desired.


Agree 100% on just showing the real code. Don't tell me what a monad is, tell me a problem I can solve with it. (I've made my own attempt at http://m50d.github.io/2013/01/16/generic-contexts.html )


>I disagree completely with his analysis on monads

You say that, but your post doesn't actually show disagreement. He said to avoid analogies, not avoid real code. His list of steps in fact contains "use monads in real code".


He's got some good stuff on his website (didn't get much from the slides as I've only dabbled in Haskell a couple times).

http://www.stephendiehl.com/posts/essential_haskell.html

http://www.stephendiehl.com/posts/types.html


Can anyone point to a similar list for Scala? I am just getting started in Scala and would love such a list.


I would suggest these for the starters: http://shuklan.com/haskell/


Wow those are some awesome lectures. Thanks!!


I'm a PHP developer and I didn't understand one single thing in this presentation. Any reason I should learn Haskell?


If you're really happy and think things are dandy and don't really have an alternative, then no, stay away from Haskell and FP. As others have commented, you will not be able to code the same way after you have learned functional programming.

While FP doesn't solve everything, it does massively reduce the amount of code you write. Where I work, I started writing everything I owned in F#. After a while, I noticed all other new projects were being written in F#, even by people that had previously told me "we are sticking with C#". Why? Because they feel bad having to write loads more code to get the same work done.

Every time I have to work in C#, I'm constantly annoyed about how verbose even the tiniest things are, how much work there is.

Beware, PHP's syntax for lambdas is incredibly verbose (and IIRC there are some odd limits on how you can use them), so if you become "enlightened" then continue to try to apply it in PHP, you are in for a rough ride. Even C# which slightly embraces functional concepts, gets pretty nasty if you write in any sort of real FP style.


Where do you work that you can just take a decision like "I'm going to use language X" if you don't mind me asking?

How did you deal with concerns (which I assume your manager must have had) about skilling up the rest of your team, and your increasing component of the bus factor? [1]

I tried to make a case for F# for some parts of our codebase and got shot down!

[1] http://en.wikipedia.org/wiki/Bus_factor


If you maintain code that is a gigantic ball of if-foreach-else-switch-is_null or your class hierarchy looks like something a Java developer would produce, and you are constantly thinking "there must be a better way," you might benefit from exploring Haskell or a language with some of its features.

PHP is actually one of those languages, since it gained real support for first-class functions, anonymous functions and closures starting with 5.3 and improving with 5.4. So if you do learn Haskell you'll be able to directly apply some of its ideas to making your PHP more concise, easier to test, and less error prone. Check out the PHP Underscore library to provide some of the infrastructure: http://brianhaveri.github.io/Underscore.php/

Haskell brings a lot more to the table than first class functions, and it may or may not be a good introduction to functional programming for you, but other functional(-ish) languages such as Scala or Clojure (or Scheme & other Lisps) will work well, too. Just give it time. It's worth the effort, but you're not going to magically transform your code into the Unicorn Monad overnight.

If you do PHP you probably do a lot of JavaScript, too, so there is another language that supports getting into functional programming, and there is definitely a lot of interest in moving JavaScript in more classically functional direction. So you won't be blindsided by maps, folds and promises.

I apologize if you already use first class functions like a boss and you were really asking if you needed static type inference. The answer is Maybe.


Functional programming is a tool. It's a really powerful tool. Knowing really powerful tools helps you solve really difficult problems.

Whether it's Haskell or some other purely functional language, I'm of the opinion that every programmer should have one in their toolset.


It's more than a tool, it's a different programming paradigm. It helps you to look at something in a different way. You can pick up a thing or two that are useful pracitices in other imperative programming languages, too.


Learn Haskell if you want your mind blown. It will make you smarter.

But there's a real danger that you will not be able to look at your own code the same way again. It can negatively affect your ability to code with your peers.

I'm not kidding. It's a blue pill/red pill kind of thing.


Nope. I see no negetive effects.

Functional programmers can write better OO code imho.


It's hard to identify a practical reason because presumably using your existing PHP stack is going to be easier for you than learning how to run a Haskell stack. Every new language comes with such barriers. It's sometimes hard to see how severe those barriers are -- I remember trying to show a totally novice-to-programming kid how to set up EasyPHP so that they could start coding. Setting up EasyPHP, which is, well, Easy, requires explaining what HTTP is and what Apache is and all that... it's actually a huge barrier to entry for a novice programmer.

But if you're OK with the impractical, here goes:

Haskell trains you to think about programming in a couple of subtly different ways that change your entire perspective.

(1) Variables are replaced with definitions and values. You probably remember HTTP as stateless and cookies as a sort of informal "patch" for this; similarly it's hard to define state in Haskell. This means that `x = [1, 2, 3];` is allowed but `x[1] = 5;` is not, because the list cannot be directly modified. This does not actually weaken the language because you can always bind new names to new values, and idiomatically you'd often use recursion -- when you want to change a parameter you arrange the code so that you can recurse and call the function again with a new parameter. It's not 100% practical but let's take the Fibonacci numbers, which you might code in PHP like so:

    function fibs($n) {
        $curr = 0; $next = 1;
        for ($i = 0; $i < $n; $i++) {
            $tmp = $curr;
            $curr = $next;
            $next += $tmp;
        }
        return $curr;
    }
In Haskell you could write this itero-recursively as:

    let fibs n = f n 0 1
      where f n curr next = if n < 1 then curr else f (n - 1) (next) (curr + next)
Notice that there's no $tmp and the named variables are now function arguments. You'll find yourself writing PHP more like:

    function fibs($n, $curr = 0, $next = 1) {
        return n < 1 ? $curr : fibs($n - 1, $next, $curr + $next);
    }
(2) Haskell is lazy. The above is actually impure because it implements `fibs` as a function when really the Fibonacci numbers are a sequence and should be treated that way. Haskell actually has no problem with defining the infinite list of Fibonaccis as:

    fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
That's a list just like any other in Haskell, it just happens to be infinite. Or, you can write the infinite list of primes:

    primes = 2 : filter prime [3..]
      where prime k = all (\n -> mod k n /= 0) (takeWhile (\n -> n^2 <= k) primes)
You will miss this a little in other languages; even Python, which can do this with custom generators, gets a little clumsy. Especially, I miss this in Node.js, where the whole language is built around an idea of "callbacks" which wouldn't need to exist if the JavaScript operators could work on deferred computations (sometimes called "promises").

(3) Haskell has a type system and explicit pattern-matching. This is a little harder to express: you're used to saying `x = my_object->x` in PHP to avoid saying "x" over and over. Let's say that the object should also have "y" and "z" fields; then you'll have to deal with cryptic errors if your function is ever called with a my_object which does not have a field named "x", but it will be okay if "y" or "z" is not allowed, even though that doesn't actually make sense really!

In Haskell you'll specify in the definition of the argument "Object x y z"; and then x, y, pattern-matching to those respective values. So your functions don't start off with a bunch of "data-extraction" commands; those commands are in the input pattern. You can also define the function when the patterns do not match, because you can define a function several times for different patterns.

The type system can also flag, for example, unsanitized text going into a SQL query and other such things you might have missed, so you can lean on it a surprising amount.

(4) The biggest thing that this page was talking about was monads, and the reason why it was talking about them is because Haskell offers a special notation for dealing with monads.

A monad is basically a context which you can't necessarily "break the data out of". For example, the "IO" monad is a context which says "this data depends on an unrepeatable IO action, like getting a random number or reading a file." You can't really erase that fact from the data, but that fact shouldn't stand in the way of handling the data. The IO monad allows you to very cleanly separate the stuff which might be different in two different runs of the program, from the stuff which is never so.

The author makes the claim that analogies are bad for understanding monads. Instead, you should just look at the definition. A monad is a typeclass which wraps another type, so the type is "M(T)" where T is any other type. A monad is defined by two functions. One is called "return" and has type T -> M(T), it puts plain data into the monad. The other function is called "bind" and accepts a function T -> M(T2), which intuitively "takes the data and feeds it to the function." The reason that you can't always "break out" of the monad is that the output of this function is M(T2), so the function output must also be in the monad. We know that "monad" is a scary-sounding word but really nobody has a better name for it.

Lists are a good monad; here `return x = [x]` and `bind xs f = concat (map f xs)`. Another simple monad is called Maybe, which can either be `Just x` or `Nothing`, it sort of represents a computation which might fail. Here `return x = Just x` and `bind Nothing fn = Nothing; bind (Just x) fn = fn x`. There's also a "State" monad, which gives you a "put" and "get" method and a scope block for typed modifiable variables, so you can have code that looks imperative -- but you've got to carefully mark it as such with the type system as a whole. The whole point being that once you allow that "put" statement you make it much harder to think about bugs because the value of the parameter will depend on where in the function that parameter appears -- so the type system acts as a warning flag.


Start here:

http://learnyouahaskell.com/chapters

This is good too, but I found it somewhat dry:

http://book.realworldhaskell.org/read/

I think that learning Haskell will make you a better programmer. It's really a different way of doing things.


There is a great point buried in slide 8. The best way to learn to use monads is...Use monads in real code.


Does anyone know the best book for learning Haskell? I have heard it is good for just thinking about programming in new ways and keeping your mind agile. I can really only learn a language with a good structured book with exercises at the end of each chapter. Haven't found something definitive yet, but would be open to suggestions.


I think "Real World Haskell" is great. If you want a more simple introduction checkout "Learn You a Haskell for Great Good!".


The 'best' introductory book for learning Haskell is Graham Hutton's 'Programming in Haskell'. It focuses on the essentials of the language, and its clear, spare presentation is in the spirit of Haskell itself. And it is accessible to everyone.


+1 for this, also check out Graham's io9 video on the Counting Problem. The solution is beautiful and really got me excited about Haskell when I was first learning:

http://channel9.msdn.com/Series/C9-Lectures-Erik-Meijer-Func...


I was actually thinking of going with this since it seemed to focus on the foundations of lambda calculus and is also fairly condensed. I was thinking I might try "The Haskell School of Expression: Learning Functional Programming through Multimedia" as a follow up just cause it sounded satisfying.


Hudak's 'Haskell School of Expression' is also full of much Haskell wisdom and spirit.


This (now closed) Stackoverflow question is a great resource:

http://stackoverflow.com/questions/1012573/getting-started-w...

Personally, I would agree with the guy that said that Learn You a Haskell and Real World Haskell are some of the best resources. LYAH is really good at explaining the language features while RWH is currently the best we have in terms of giving practical examples with real libraries and things like that.


Slides don't work in Sarari on iOS. Is there a static version?



Finally a proper answer. Thanks!


This is a tech forum. We do cool new stuff, not make stuff accessible to a wide audience using ancient technology from last week.


iOS is ancient technology now? Is that why you [or whoever] downvoted me? What the hell?


Wonder if there's any good joke and sacrasm detector app on AppStore.


I don't think he downvoted you.


Is there a recording of a talk to match these slides?


This post somehow triggered me to grab "Learn You a Haskell for Great Good" this morning and I have been gorging on it since then. I've had quite a few "holy shit" moments.


Pretty comprehensive (including plenty of things I haven't had time to look at into more details yet). Bonus points for using applicative style, which makes it a lot easier (and clearer) to apply function to value inside monads.


"Haskell Propaganda: OOP programming couples code and data together in unnatural ways. Typeclasses are a better way of structuring logic."

should be

"Inheritance couples code and data together in unnatural ways. Typeclasses are a better way of structuring logic."


How so? An OOP language without inheritance would still be coupling code and data together "in unnatural ways". It is the object that is doing the coupling, not inheritance.


Some of the slides need explanation.

What is the value of -ddump-simpl as shown here? http://dev.stephendiehl.com/hask/#%2816%29


As freyrs points out, GHC "desugars" all Haskell code into a very small intermediate language that is similar to the System F lambda calculus. In the slide you linked you can kind of see that: you start with two doubles for 2 and 3 (created wit the `D#` function) and then you add them with the addition operator. Notice that this exposrs the implementation of typeclasses: the overloaded + operator is actually a function of three arguments and the first argument is the "vtable" that has the actual number operations.

I don't know why he is doing all of this though. The slides themselves don't give much context...


It dumps the internal Core representation of expression. It's closer to the lambda calculus ( System F ) and a good way to understand internals.


Nothing like getting a pile of slides without any presenter notes or anything else helping to interpret the slides.


This is very good. I'm getting a bunch of new tricks out of this even though I regularly use these libraries.


Recording would be great! I feel like I only got half of the (good) information without it.


I first learnt Haskell ten years ago for a class. Mostly toy problems. Looking to get back into it. What books are good to learn to build actual apps - especially user input, UI, etc.?


realworldhaskell is good for general purpose.

i think the yesod o'reilly book (free on yesodweb.com) is a very good one if you dont mind to make web apps.


I saw a blank page and immediately thought "how poetic".




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: