Live data from Hacker News

A difference between Haskell and Common Lisp

chrisdone.com

41–50 of 203 posts

Re: A difference between Haskell and Common Lisp

#42
post #27

Is this really a philosophical difference? Granted, I've only used Clojure as far as Lisps go, but composability seems to be something that's emphasized. Rather than (remove-if-not #'p xs :count 5 :start 3) It seems to me like most Clojure users would do something like (->> xs (drop 3) (filter p) (take 5)) which is much closer to take 5 . filter p . drop 3

Is not the same, in lisp :count 5 means that you remove at most 5 elements, so that the result can be a list of 100 elements, while take 5 will always produce a sequence with at most 5 elements. (remove-if-not #'evenp (loop for i below 10 collect i) :count 3 :start 0) result is (0 2 4 6 7 8 9), there are three elements deleted.

Well, that is different, but I suppose the Haskell example suffers from the same difference then.

Re: A difference between Haskell and Common Lisp

#44

Common Lisp has these kitchen-sink functions and macros because it was a standard developed by a committee whose goal was to incorporate several popular implementations of Lisp that each had several decades worth of of cruft. Lisp was big enough business at the time that having several mutually incompatible versions of Lisp was making knowledge sharing and business difficult. And having a standard was important for m…

The theoretical foundation of Haskell is a typed lambda calculus called System F-omega. GHC Haskell has some additional features that are inexpressible in System F-omega.

There you go. Lisps tend to implement the untyped lambda calculus. Not too surprising or interesting...

Re: A difference between Haskell and Common Lisp

#45

Earlier quoted context omitted.

The theoretical foundation of Haskell is a typed lambda calculus called System F-omega. GHC Haskell has some additional features that are inexpressible in System F-omega.

There you go. Lisps tend to implement the untyped lambda calculus. Not too surprising or interesting...

Lisp is far from any lambda calculus, even the untyped one. Lambda calculi don't have variadic functions, or any means to inspect their own syntax. Lambda abstraction is called abstraction for a reason - you can't inspect the expression inside. Lisp is really its very own kind of thing, which can be both very interesting (if you care about extensibility) and very irritating (if you care about abstraction). Racket, a dialect of Scheme, is the only serious attempt so far at providing an extensible language that protects user-defined abstractions.

Re: A difference between Haskell and Common Lisp

#46

I'm confused by the last example. There are no elements greater than 5 in the list (1 2 3 4). Also, I'm not sure why they used takewhile instead of filter in the last haskell part.

I assumed it to be a typo; i.e., it should say "less than". `takeWhile` is different to `filter` in that is returns the input list until some element matches the predicate, whereas `filter` returns all elements that match the predicate. For example, if the predicate is `(< 5)` and the input was `[9, 2, 3, 6]`, then `takeWhile` would return an empty list, but `filter` would return `[2, 3]`.

He should have used a better input, though, maybe 1, 2, 3 ,4 ,5. With the given input it's a bit confusing, it's equivalent to filter . even [1..4]. Also, the Lisp loop should have been checking for (>= i 5), to be equivalent to the Haskell example.

Re: A difference between Haskell and Common Lisp

#47
post #26

Earlier quoted context omitted.

One could also change the Haskell. Data.Function (&); Control.Arrow (>>>) -- the pipe operator seems to be all the rage these days (|>) = (&) -- forward application + forward composition xs |> (drop 3 >>> filter p >>> take 5) Only function application xs |> drop 3 |> filter p |> take 5

I never understood the appeal of the pipe operator. It's a kludge to work around the need to eta-expand chained function compositions, which in turn is a kludge to work around the value restriction, which in turn is a kludge to prevent the combination of polymorphism and storage effects from breaking type soundness. Haskell doesn't need any of this.

I agree with you. I'm going to write a post about function application and composition (right-to-left / left-to-right) so other communities can stop discussing non-essential matters.

I do like the fact that the `pipe operator` is often mentioned along the bash '|' which is used in a pointfree style.

Well it might make sense sometimes, so its good to know one's options :)

  p x y z = f (g x y) z
  p       = ((.) f) . g

Re: A difference between Haskell and Common Lisp

#48
post #30

Actually Common Lisp supports a gazillion of different programming styles. The version with small functions, similar to the Haskell version: (subseq (remove-if (complement #'numberp) (butlast list 3)) 0 5) In above Common Lisp code, we use four different functions which do one task: * subseq sequence start &optional end => subsequence * remove-if test sequence => result-sequence * complement function => complement-fu…

> Check out the UNIX man for tail, grep, ... to see how strange above quote about 'unix philosophy' is.

I wish someone would take that hoary old meme out behind the barn and put it out of our collective misery.

Re: A difference between Haskell and Common Lisp

#49
post #30

Actually Common Lisp supports a gazillion of different programming styles. The version with small functions, similar to the Haskell version: (subseq (remove-if (complement #'numberp) (butlast list 3)) 0 5) In above Common Lisp code, we use four different functions which do one task: * subseq sequence start &optional end => subsequence * remove-if test sequence => result-sequence * complement function => complement-fu…

That `butlast` removes the last three elements, but here you were supposed to remove the first three elements. So I guess `cdddr` is what you need.

Also, the way the article uses `remove-if-not` is all wrong. The `:start` argument to `remove-if-not` doesn't mean it starts taking elements after the third one, rather it means it starts filtering after it. So

  (remove-if-not #'evenp '(1 2 3 4 5 6) :start 3)
doesn't produce (4 6) as the article assumes. It produces (1 2 3 4 6).

And the `:count` argument doesn't mean it returns 5 elements, rather it means it removes 5 elements. So

  (remove-if-not #'evenp '(1 2 3 4 5 6) :count 1)
returns (2 3 4 5 6).

Re: A difference between Haskell and Common Lisp

#50
post #47

Earlier quoted context omitted.

I never understood the appeal of the pipe operator. It's a kludge to work around the need to eta-expand chained function compositions, which in turn is a kludge to work around the value restriction, which in turn is a kludge to prevent the combination of polymorphism and storage effects from breaking type soundness. Haskell doesn't need any of this.

I agree with you. I'm going to write a post about function application and composition (right-to-left / left-to-right) so other communities can stop discussing non-essential matters. I do like the fact that the `pipe operator` is often mentioned along the bash '|' which is used in a pointfree style. Well it might make sense sometimes, so its good to know one's options :) p x y z = f (g x y) z p = ((.) f) . g

Of course, something is very wrong if you ever use a section of the function composition operator. Use point-free within reason... :-p
Post reply on HN