Live data from Hacker News

A philosophical difference between Haskell and Lisp (2015)

chrisdone.com

21–30 of 181 posts

Re: A philosophical difference between Haskell and Lisp (2015)

#21

Earlier quoted context omitted.

Not super familiar either language, how does lazy evaluation promote the use of smaller functions?

In non-lazy languages you would need to implement laziness to manage composing functions and have good performance. An example being take 5 . filter ... If evaluation wasn't lazy you would run take 5, return the result to filter and so on.

In the languages I use (Scala, Ruby) it's already done, Rust is using iterators which are lazy too. None of those languages are "lazy" in Haskell sense.

Re: A philosophical difference between Haskell and Lisp (2015)

#22
I dislike the lisp convention of remove-if, remove-if-not, etc. Filter and take isn't much better. The python convention is much nicer:

  [x for x in foo if x not in y]
Turns out, this can be expressed in Lisp:

  (list x for x in foo if x not in y)
I've implemented this into my fork of Lumen that runs on Python. https://github.com/shawwn/pymen It feels very nice to use:

  > (list x for x in (range 10) if (= (% x 2) 0))

  """
  Built-in mutable sequence.

  If no argument is given, the constructor creates a new empty list.
  The argument must be an iterable if specified.
  """
  [0, 2, 4, 6, 8]
  >
It wasn't even that ugly to implement. It's ~20 lines: https://github.com/shawwn/pymen/blob/1c191c9e00e73303a6479f8...

One other neat thing is that the REPL prints out the docstring of the last evaluated thing by default. It makes it nice to explore libraries:

  > (import numpy as np)
https://imgur.com/1rpF95y

  > np.vsplit
https://imgur.com/OjIvTWt

It's like an automatic help() call on the last evaluated thing.

(If anyone happens to try it out, you can get into a REPL by running `rlwrap bin/pymen`, or just `bin/pymen`.)

Re: A philosophical difference between Haskell and Lisp (2015)

#23
Javascript and Python have similar capabilities, but they're missing the stream fusion optimization mentioned at https://chrisdone.com/posts/stream-composability/

Javascript:

  a = [...Array(20).keys()]
  p = x=>!(x%2);
  a.slice(3).filter(p).slice(0,3)
Python:

   a = range(20)
   p = lambda x: not x%2
   filter(p, a[3:])[:3]

Re: A philosophical difference between Haskell and Lisp (2015)

#24
post #7

This is interesting to read having worked with Clojure, but never Haskell or CL. I expected the Haskell examples to look alien and the CL to look familiar, but the idiomatic Clojure solutions to the examples are almost identical to the Haskell solutions. E.g. take 5 . filter (not . p) . drop 3 becomes (->> s (drop 3) (filter (complement p)) (take 5)) ; for some sequence s I think it is also true of Clojure that it st…

Is there something similar to (->>) in Haskell? Edit: corrected “—>”.

`.` is function composition in Haskell (used in the example).

Re: A philosophical difference between Haskell and Lisp (2015)

#26
post #7

This is interesting to read having worked with Clojure, but never Haskell or CL. I expected the Haskell examples to look alien and the CL to look familiar, but the idiomatic Clojure solutions to the examples are almost identical to the Haskell solutions. E.g. take 5 . filter (not . p) . drop 3 becomes (->> s (drop 3) (filter (complement p)) (take 5)) ; for some sequence s I think it is also true of Clojure that it st…

Is there something similar to (->>) in Haskell? Edit: corrected “—>”.

You can create it yourself:

    Prelude> s ->> f = f s
    Prelude> [1..100] ->> take 10 ->> filter (not . odd) ->> drop 3
    [8,10]

Re: A philosophical difference between Haskell and Lisp (2015)

#27
post #7

This is interesting to read having worked with Clojure, but never Haskell or CL. I expected the Haskell examples to look alien and the CL to look familiar, but the idiomatic Clojure solutions to the examples are almost identical to the Haskell solutions. E.g. take 5 . filter (not . p) . drop 3 becomes (->> s (drop 3) (filter (complement p)) (take 5)) ; for some sequence s I think it is also true of Clojure that it st…

Is there something similar to (->>) in Haskell? Edit: corrected “—>”.

Not really. In the example, function composition, `.`, joins the functions together.

You can smash a list of functions together but they'd all have to take and return the same type, and the list would introduce commas and square brackets, so it wouldn't look quite the same.

Re: A philosophical difference between Haskell and Lisp (2015)

#28
post #10

Earlier quoted context omitted.

For one Lisp is not lazy like Haskell.

The article elaborates on this point a bit: > Like pipes in UNIX, the functions are clever enough to be performant when composed together–we don’t traverse the whole list and generate a new list each time, each item is generated on demand. In fact, due to stream fusion, the code will be compiled into one fast loop. I imagine it is hard to do the same optimization in a non-lazy language.

It's interesting that he says you also need purity to do the optimization, but Unix pipes are not necessarily pure.

Re: A philosophical difference between Haskell and Lisp (2015)

#29
post #23

Javascript and Python have similar capabilities, but they're missing the stream fusion optimization mentioned at https://chrisdone.com/posts/stream-composability/ Javascript: a = [...Array(20).keys()] p = x=>!(x%2); a.slice(3).filter(p).slice(0,3) Python: a = range(20) p = lambda x: not x%2 filter(p, a[3:])[:3]

You can also do this nicely in Linq in C#.

Re: A philosophical difference between Haskell and Lisp (2015)

#30
post #8

Earlier quoted context omitted.

I don’t understand why the above got down-voted... Without fusing (lazy) loops, having a bunch of independent sequential transformations (each with its own loop) can make the same computation significantly slower!

Ruby or Scala don't have lazy evaluation by default, yet there are views (Scala) or lazy (Ruby), so no, you don't necessary need compiler help.

Yeah, you can emulate laziness at the library level with iterators, coroutines and whatnot, but it always comes with a certain API friction (some readers might be familiar with the “colored functions” analogy [1]) compared to Haskell’s approach that takes laziness to the extreme.

[1] http://journal.stuffwithstuff.com/2015/02/01/what-color-is-y...

Post reply on HN