Live data from Hacker News

A philosophical difference between Haskell and Lisp (2015)

chrisdone.com

91–100 of 181 posts

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

#91

Uh guys? [1]> (remove-if-not #'evenp `(1 2 3 4 5 6 7 8 9 10) :count 3 :start 1) (1 2 4 6 8 9 10) As pointed out by owl57, the Haskell translation is incorrect and the correct implementation isn't quite so trivial. I don't see a way to pull the :count argument out into a separate function. We certainly can for skip, though, and I might. Prelude> skipThen 1 (removeIfNot even 3) [2,3,4,5,6,7,8,9] [2,4,6,8,9] as implemen…

You’re lisp syntax is weird but you’re right:

The start argument specified where to start removing things and the end or count arguments specify where to stop removing things (ie at an index or after a certain number of elements respectively).

I claim this is a pretty good argument against the keyword arguments as they don’t necessarily do what one expects.

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

#92

Earlier quoted context omitted.

I followed a (pure) mathematics education, and I totally dig lisp. On the other hand, I abhor haskell and hate almost everything about it!

I also followed a pure maths education. I like lisp (in the CL/emacs lisp family more than scheme which tends to have smaller composable functions) and Haskell. I find some parts of Haskell culture/styles to be quite silly however, and fewer parts of the lisp community to be silly. But that may just be because of Haskell’s greater popularity.

is haskell more popular now? what about clojure?

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

#93

Earlier quoted context omitted.

For those that didn't know, Haskell does of course have list comprehensions: [x| x Here's an example finding consonants: [c| x

No need for the dollar sign in the second example :) A nice thing about Haskell list comprehensions is they're based on a trivial transformation to monad syntax, which makes it easier to factor out complex list transformations into multiple little bites. I've run into this problem in Python. Also, Python list comprehensions can often behave very unexpectedly due to mutability. Here's an example of the monad syntax: […

Example where Python list comprehensions behave very unexpectedly...?

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

#94
post #40

Earlier quoted context omitted.

Unix pipes don't do stream fusion, which is the optimisation to which he was referring.

So if I put (x1, x2...) through pipes f and g, instead of calculating all the f(x)s first followed by all the g(f(x))s, it calculates g(f(x1)), then g(f(x2)), etc. How is that order of operations different to stream fusion? Why does stream fusion require more purity than Unix pipes?

Let's say there's a global mutable variable M (doesn't have to global, can be x1.M = M, x2.M = M, for example, but easier to think with global) which is used by and modified when f(x) or g(y) runs. Then, the order of operations would matter and so you get different results with and without stream fusion.

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

#95
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 did find it ironic that composition was called UNIX philosophy, when most UNIX tools are complicated functions with many options much more akin to the lisp function examples. (Of course it's the "UNIX pipes" part of the philosophy that's being alluded to, but it's still a funny twist)

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

#96
post #50

Earlier quoted context omitted.

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…

Using right-associativity of function types, and by sugaring the lambda into another function argument, we can rewrite this as

  (*-) :: (a -> b -> c) -> b -> a -> c
  (*-) f x y = f y x
This reveals that (*-) is simply flip, which is in the Prelude (re-exported from Data.Function). Alternatively, Hoogling the original type signature will reveal the same thing.

So the example doesn't require any new functions:

  import Data.Function ((&))

  xs :: [Int]
  xs =
    5
      & flip take [1, 2, 3]
      & filter (/= 1)
      & head
      & flip take [1, 2, 3]
In general, it's common in Haskell to use flip, curry/uncurry, and other higher-level functions to manipulate functions so they fit into the needed context.

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

#98
post #16

Common Lisp doesn’t just have LOOP, it also has Series [1]. I think the actual philosophical difference may be that Haskell does this with compiler support for stream function composition, whereas Common Lisp does it with a set of language-level macros any user could write (if they were as smart as Richard Waters). [1] https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node347.html

Strictly speaking, Common Lisp does not have series because they were not included in ANSI Common Lisp. Therefore even though you could use the macros provided with a separate streams package, you’d need to make sure that all your code used that package (rather than the CL definitions of let and lambda and so on) and properly declared stream functions. This ends up making code using streams not super composable which…

My impression was some of those expressions were added to the compiler specifically to make stream fusion work well enough to use. Even if so, it’s a good point that laziness makes streams more “natural” in Haskell so that was just a performance improvement, not a semantic change. Certainly laziness is a big “philosophical difference” between the two!

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

#99
post #3

Any particular reason why Lisp doesn't also tend to compose with smaller functions? Did it just happen to evolve that way? Is it easier to get the types of the smaller functions right when you have a compiler to help you like you do in Haskell?

For one Lisp is not lazy like Haskell.

I'm sure you (OP) are aware, but just in case others aren't: Clojure stands out as a Lisp that embraces laziness.
Post reply on HN