Live data from Hacker News

A philosophical difference between Haskell and Lisp (2015)

chrisdone.com

61–70 of 181 posts

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

#61

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)) """…

Huh, the syntax can be almost directly spliced into Common Lisp's loop:

  CL-USER> (let ((foo '(1 2 3)) (y '(2 4)))
             (loop for x in foo unless (member x y :test #'=) collect x))

  ;; -> (1 3)
It wouldn't be hard to write a macro that expands your expressions to CL's loop, with a bit of magic to parse the "if ... [not] in ...".

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

#62
There's a more fundamental philisophical difference:

Common Lisp promotes the use of doclines and apropos tools in order to discover and understand behaviour, with symbol names that tend to describe the function of what they represent.

Haskell leans on type signatures and symbolic operators.

IMHO, a pseudo-random sequence of non-word symbols tied to a type signature is of very little use.

IE, something fabricated:

    (-*/) :: A -> M c -> B
Ah yes, so understandable.

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

#63
post #50

Earlier quoted context omitted.

This comes for free from Haskell's automatic partial application (that arises from Haskell's pervasive use of function currying). So several different Haskell variants of Clojure's `compose` correspond to different versions of Clojure's threading macros. Clojure's threading macros arise because it's a little bit more awkward in Clojure to partially apply functions (either anonymous functions with # or use `partial`)…

What's the syntax in Haskell for thread-first (-> in Clojure) which inserts the result of the previous operation as the first argument, versus thread-last (->>) which inserts it at the end, so is more amenable to composed curried functions?

Ah I was wrong! That's what I get for not coding in Haskell in a year and not checking my answer with GHC.

Function application always has higher precedence than infix operators so I can't emulate thread-first with functions in Haskell. If that wasn't the case, this would work (this was what I was thinking of)

    (|*>) :: b -> (a -> b -> c) -> (a -> c)
    (|*>) x f = (\y -> f y x)

    xs = 5
        |*> take [1, 2, 3]
Otherwise, I can come close with this.

    import Data.Function ((&))

    infix 9 *-
    (*-) :: (a -> b -> c) -> b -> (a -> c)
    (*-) f x = (\y -> f y x)

    xs :: [Int]
    xs = 5
        & take *- [1, 2, 3]
        & filter (/= 1)
        & head
        & take *- [1, 2, 3]

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

#64

Earlier quoted context omitted.

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...

I was really hoping that article was going to start talking about effect systems. They're so cool! They make it possible to have many different function colors without it being a huge chore. They can be thought of as a more-ergonomic generalization of monads.

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

#65
The main difference is that in lispy languages you wouldn't use the language itself to solve the problem. You'd extend it. I'd write a function that is (drop3-take5 test list) which does exactly what it says.

This might seem like huge overkill, but when the specs change and I need to set the start and stop from a config file I can easily refactor drop3-take5 into (drop-n-take-m n m test list), with a let around it to read the config.

drop3-take5 would look something like:

    (define drop3-take5-list
      (lambda (ls filter)
        (define internal
          (lambda (ls matches)
            (cond
             ((null? ls) '())
             (else
              (if (filter (car ls))
                  (cond
                   ((

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

#66

Earlier quoted context omitted.

This comment would be more informative if you briefly explained why you abhor it and hate almost everything about it.

Yep, sorry. This is a matter of feeling, completely irrational, but just my experience. When I program in lisp I get the same feeling when I'm solving an ODE by hand, or a Diophantine equation, or designing a numerical method to approximate the solution of a PDE, or finding the Euler-Lagrange equations of a physical problem. The thing is real and it gets shit done really fast; it is just exhilarating. Moreover, lisp…

Is it the type system?

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

#67
post #48

A small note: composition is not better than monolithism. The article makes it feel like it is but it is not. They are two perfectly valid approaches when it comes to solving problems. Often a mix of both is used. Monoliths tend to be better at solving common real life problems efficiently while composition is better suited for unexpected abstract problems. We need both. For example GNU binutils are not very "unixy",…

I disagree. With composition we have general building blocks which can be combined in an infinity of ways, and remain available to combine with newly added functions. The monolith way provides a fixed, non upgradable set of possibilities, so if your need does not fall into what already exists you need to add yet another monolith (see remove-if vs remove-if-not).

I mean the -if vs -if-not is really more for typing convenience, the current CL standard actually recommends against -if-not functions because you can do composition `(remove-if (complement #’predicate) sequence)`

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

#68
post #48

A small note: composition is not better than monolithism. The article makes it feel like it is but it is not. They are two perfectly valid approaches when it comes to solving problems. Often a mix of both is used. Monoliths tend to be better at solving common real life problems efficiently while composition is better suited for unexpected abstract problems. We need both. For example GNU binutils are not very "unixy",…

I disagree. With composition we have general building blocks which can be combined in an infinity of ways, and remain available to combine with newly added functions. The monolith way provides a fixed, non upgradable set of possibilities, so if your need does not fall into what already exists you need to add yet another monolith (see remove-if vs remove-if-not).

Change the Haskell example to read 3 and 5 as n and m from an external file. All of a sudden your beautiful code is now a huge mess and you need to refactor the one liner into at least three separate functions to try and keep the Maybe types from taking everything over.

Meanwhile in lisp I would have written a special drop3-take5 function in the first place. Then refactoring it would just take replacing 3 with n and 5 with m, adding n and m as arguments and writing a function to read whatever the config file is.

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

#69
This is really just talking about which functions they decided to include in their standard library. Clojure for example takes the haskell approach so its not a question of composability vs monolith.

Sure composability is nice and should probably be the way you start creating something but after you are satisfied that it works the way you want it to and you want to make it more efficient you will go monolith and treat this new thing as a bigger piece you can compose with.

Someone new can the come along, fail to understand why its a monolith and decide to make it better my making it made up of composable parts again.

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

#70
> One difference in philosophy of Lisp (e.g. Common Lisp, Emacs Lisp) and Haskell is that the latter makes liberal use of many tiny functions that do one single task. This is known as composability, or the UNIX philosophy.

This honestly seems like a misunderstanding which ignores how many POSIX commands actually accept commands. The uni philosophy doesn’t mean literally one thing, but rather one task; sometimes the task will have different parameters and that’s OK, but we’re not going to have `ls` takeout the trash.

Post reply on HN