Live data from Hacker News

A philosophical difference between Haskell and Lisp (2015)

chrisdone.com

81–90 of 181 posts

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

#81
post #74

Earlier quoted context omitted.

People who write Haskell don't just leave their symbolic operators undocumented. It's definitely heavy on the symbols but that and type signatures are certainly not the only tools Haskell devs have.

On the one hand, the parent's comment is certainly hyperbole. On the other hand, it's also the case that too any Haskell projects are under-documented. Probably worse than the typical language, and certainly worse than the best-in-class. On the gripping hand... while types make poor documentation, they are always correct documentation, and they are automatically generated documentation. When I write Python or (appare…

I find type information for functions incredibly useful. I get so lost in Python code once it get past a certain size even after years of Python programming experience because of the its lack of ability to put a useful amount of structure into the code. After having programmed in Haskell for a while, I just miss tabbing a function and being able to see its type signature.

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

#82

There is a strange... kind of poetry with Haskell. It is like math on wheels, math applied to procedures, math with... time. Its appeal to me is like the appeal of math to me, not like real analysis math but abstract algebra math. The beauty, the purity of mathematics of younger days that once became lost after encountering the sad complexities of the world. Understanding every little aspect and being able to prove e…

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

Me too and I like Haskell the most just because I feel like it's closer to math than clojure.

If I want to solve a problem I can think of it a a series of maps f: X -> Y and once I solve it on paper "translating" into Haskell just feels natural.

It's also super easy to do that in clojure, maybe I'm just baised because I found and learned Haskell first.

Now days I use clojure for everything and it's amazing. I never enjoyed programming so much until I discovered the functional paradigm. It just feels right.

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

#83
post #77
post #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…

This seems like an unsustainable approach: will you need to write these bespoke functions for any combination of behaviors you would need?

Lisp is about writing a dsl that solves your problem. It just happens to be an s-expression dsl. Exactly how it works depends on the problem domain. But in my experience a lisp dsl is much less brittle than trying to map the problem into a haskell program, especially with a changing spec.

This is a bad example because it is so contrived to show off the strengths of haskell.

As an example for the strengths of lisp: I wrote a logical dsl that adds a boolean dependent type system to scheme using macros. It's 400 lines long and copies all the bits from Idris I needed and it still feels like a scheme and is fully interoperable with regular scheme.

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

#84
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 isn’t great.

I also think it’s a bit unfair to say that Haskell’s stream fusion requires special compiler support. The compiler doesn’t recognise list functions specifically or have special cases for list-looking-types (except for syntax). Instead there is a general mechanism to say “at stage number x, replace expressions that look like y with z”, where there are something like 10 stages and expressions y and z are type checked so these transformations are only applied in “valid” cases. I think saying that this is special compiler support for stream fusion is like saying that macros are special compiler support for series in CL.

A final thing to note is that because of lazy evaluation, stream fusion in Haskell doesn’t change the semantics of the Haskell list functions from how they would behave without it. In Common Lisp streams must be explicitly separated from lists because they are semantically different (in the evaluation order of the functions that act on them).

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

#85
post #68

Earlier quoted context omitted.

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…

keep the Maybe types from taking everything over.

Pattern matching on Maybe types is rather unidiomatic Haskell. Much better to take advantage of the type classes to which Maybe belongs: Functor, Applicative, Monad. In particular, there's no need to unwrap/wrap the Maybe value when you have `fmap`.

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

#86
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 implemented:

    removeIfNot p count = go count
      where
        go _ [] = []
        go 0 list = list
        go n (x:xs) | p x = x:go n xs
                    | otherwise = go (n - 1) xs

    skipThen count f list =
        let (pre,suf) = split count list
         in pre ++ f suf

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

#87
Deeper philosophical differences:

* Lisp is multi-paradigm languages. Haskell is pure functional language.

* Haskell wants to be mathematics. Lisp wants to be an operating system.

I believe the composition vs. monolithism difference comes from these deeper differences.

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

#88
I think it should be stressed that most languages (except maybe bash I guess) can’t provide the kind of compositionality that Haskell does.

This is because Haskell’s lazy evaluation allows these compositions to do an asymptotically appropriate amount of work. Consider this Haskell:

  xs = [1..20]
  p n = if n 
If a strict language were being used then the processing would be as follows:

1. drop 3 ys is [4..20] 2. When computing filter p [4..20], everything is ok up to 12, but computing p 13 goes to an infinite loop. 3. We never get a result to compute take 5 of.

Because Haskell is lazy, it will not try to compute p 13 and so can do the right amount of work.

Perhaps a more reasonable example would be that if the list xs were really long, a strict program would have to evaluate p against every element before taking the first 5 results (so it would take linear time if p were constant time) while a lazy program would only need to compute p on enough elements to collect 5 results.

Common Lisp was designed for older, slower computers than Haskell and to be able to make programs which were reasonably efficient. It also had strict evaluation and so with this context, the extra arguments to many functions for special cases (which lots of people didn’t like) or the combined iteration of loop (which lots of people didn’t like) make a lot more sense.

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

#89
> One difference in philosophy of 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.

Have you ever looked at a Unix man page?

And while Common Lisp has some functions that might be swiss army knives of functionality, that is not "the philosophy of Lisp", it's a particular style. Clojure and Scheme are just as much Lisp as CL, and as other people have noted, their style is very similar to Haskell.

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

#90
When I started out with Python, I was learning Haskell in parallel. As a result, my early Python code ended up being influenced by Haskell (I wrote many small functions that performed a single task). But it was somewhat frustrating. Later, I developed my Python style and began heavily relying on optional arguments through `kwargs` and duck typing. That made my programs much more effective and easier to reason about. Now I realize that my later Python code became more Lisp-like.
Post reply on HN