Live data from Hacker News

A philosophical difference between Haskell and Lisp (2015)

chrisdone.com

161–170 of 181 posts

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

#161
post #130
post #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 let's try to assign some meaning to this. From the get go, you know that it's a function that turns an A into a B, and it only has the information that is derivable from `M c`. So, yes this is gibberish. But if there's a slight modification to this: (-*/) :: A -> M c -> c then it makes a lot of sense. Signatures are a much shorter, terser way to communicate than words (and nesting structures…

It was meant to be pithy jibberish, yes; I tried to pick three characters in an operator that I was semi-confident that I hadn't seen while writing Haskell, and a garbage signature.

But even with your alteration, I'm not sure what it does. What interaction is there between A and M c? Does it mutate c, or just unwrap it?

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

#162
The main difference is that Haskell is a very specific language, whereas Lisp is a family. Not all the members of the family are based on exactly the same philosophy.

The remove-if-not function just a Common Lisp thing.

And, by the way, at the bottom of its description in the standard, we find this:

The functions delete-if-not and remove-if-not are deprecated.

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

#163

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…

Thank you, I've mailed author, he updated the post

> UPDATE 2020-08-03: I no longer stand by the content in this post. I think the overall sentiment is marginally accurate; however, the details in the post are incorrect (as many have pointed out over the years).

> As has been pointed out, remove-if-not’s start/count parameters behave differently and cannot easily be separated out of the function, a design trade-off that I appreciate.

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

#165
post #81

Earlier quoted context omitted.

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.

That, and more, is available in common lisp.

    * (describe #'+)
    #
      [compiled function]
    
    
    Lambda-list: (&REST SB-KERNEL::NUMBERS)
    Declared type: (FUNCTION (&REST NUMBER) (VALUES NUMBER &OPTIONAL))
    Derived type: (FUNCTION (&REST T) (VALUES NUMBER &OPTIONAL))
    Documentation:

      Return the sum of its arguments. With no args, returns 0.

    Known attributes: foldable, flushable, unsafely-flushable, movable, commutative
    Source file: SYS:SRC;CODE;NUMBERS.LISP
Docstrings and type information can (optionally, but recommended) be added to all code. Users of your API can use documentation/describe to discover information about it without ever having to look at the implementation.

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

#166
post #105

Earlier quoted context omitted.

Lisps lack implicit currying, so function composition becomes much more verbose. And functions aren't that important in CL, not everything is a function and CL is usually written in an OOP or procedural style. CL is more about data and AST composition then anything else. Moreover, CL is a lisp-2, so in a very real sense, functions are second class citizens in the language.

Or, you use reader macros to make currying concise. https://github.com/eschulte/curry-compose-reader-macros Functions are not second class citizens. They are privileged with their own namespace. That's a perk, not a penalty. One notable form of composition in CL is method combination. Does any other language support something like that?

Having to prefix functions with #' is a perk? No other language uses a separate name space for functions, and for good reason, because it sucks.

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

#167

The main difference is that Haskell is a very specific language, whereas Lisp is a family. Not all the members of the family are based on exactly the same philosophy. The remove-if-not function just a Common Lisp thing. And, by the way, at the bottom of its description in the standard, we find this: The functions delete-if-not and remove-if-not are deprecated.

That deprecation is meaningless, since there is no standard body to revise the standard, and users are perfectly willing to continue to use those functions.

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

#168
post #166

Earlier quoted context omitted.

Or, you use reader macros to make currying concise. https://github.com/eschulte/curry-compose-reader-macros Functions are not second class citizens. They are privileged with their own namespace. That's a perk, not a penalty. One notable form of composition in CL is method combination. Does any other language support something like that?

Having to prefix functions with #' is a perk? No other language uses a separate name space for functions, and for good reason, because it sucks.

It's an optimization for usability. Many more symbols occur as the heads of list forms than appear after #'. So, the common case is optimized for clarity and the relatively uncommon case requires two extra characters.

I completely disagree that it sucks. What sucks is having to remember not to have your variable names collide with your function names (or indeed any of the other namespaces in CL). Things that are usually used in different ways benefit from having separate namespaces.

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

#169
post #144
post #126

Earlier quoted context omitted.

Math with time (and space/memory)... You just found the difference between computer science and math. And the reason proof-of-work in blockchains is possible.

Regarding time... It's sometimes not easy to say what happens when in a Haskell program. Yes, monads give you a sequence, but it's usually not the one sequence of an imperative language.

Indeed. And while monads provide a certain kind of sequence, it's important to remember that what is being sequenced is just some data dependencies—later effects can depend on the result of earlier effect. The evaluation order can be completely different depending on the type of monad and how the data is actually used. For an extreme example, take the forward & backward state (or "Tardis") monad[1], or for that matter any monad that implements MonadFix (including IO). The fact that the code is written in some order using a monad does not imply that it gets evaluated in that same order.

[1] https://hackage.haskell.org/package/tardis-0.4.1.0/docs/Cont...

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

#170
post #130

Earlier quoted context omitted.

> (- /) :: A -> M c -> B let's try to assign some meaning to this. From the get go, you know that it's a function that turns an A into a B, and it only has the information that is derivable from `M c`. So, yes this is gibberish. But if there's a slight modification to this: (-*/) :: A -> M c -> c then it makes a lot of sense. Signatures are a much shorter, terser way to communicate than words (and nesting structures…

It was meant to be pithy jibberish, yes; I tried to pick three characters in an operator that I was semi-confident that I hadn't seen while writing Haskell, and a garbage signature. But even with your alteration, I'm not sure what it does. What interaction is there between A and M c? Does it mutate c, or just unwrap it?

It can't mutate `c` because it doesn't know what `c` is. There might not even be a value to mutate; `c` could be Void, or a phantom type parameter. But given a definition for `M c` like:

    data M c = M (A -> c)
there would only be one reasonable implementation:

    a -*/ (M f) = f a
If `M c` does not contain a function from `A` to `c` then the only possible result is non-termination. You weren't given a value of type `c`, and you have no way of producing one from the inputs, so you can't return such a value, and the only alternative is not returning at all.

Of course the real problem here is that (at least without context) this operator name doesn't mean much. You could make the same complaint about a perfectly ordinary function named `ixfni`. The only real difference in Haskell is that symbolic operators is written infix by default, while named functions are written prefix, but it's very easy to flip that around:

    (-*/) a b
    a `ixfni` b
Note that you can even define fixity and precedence for named functions in their infix forms. Unlike most other languages with user-defined operators there is remarkably little pressure to rely on symbols in situations where they would be unclear. Symbolic operators should only be defined in situations where the symbols are reasonably well-known (within some context) or "intuitively" related to existing operators.
Post reply on HN