3 ms·
There's a more fundamental philisophical difference: Common Lisp promotes the use of doclines and apropos tools in order to discover and understand behaviour,
by dleslie 6y ago
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.
- vore 6y agoPeople 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.
- dllthomas 6y agoOn 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 (apparently) Common Lisp, I can expect to get reasonable documentation by interrogating anything someone hands me. In Haskell, insofar as I have learned to get good information from the types, I get some (correct!) documentation for things that I have newly assembled myself!
- newen 6y agoI 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.
- dleslie 6y agoThat, and more, is available in common lisp. * (describe #'+) #<FUNCTION +> [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.
- chii 6y ago> (-/) :: 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 that LISP uses) imho.
- dleslie 6y agoIt 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?
- nybble41 6y agoIt 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.
- MaxBarraclough 6y ago> IMHO, a pseudo-random sequence of non-word symbols tied to a type signature is of very little use. Having only ever dabbled in Haskell, I feel the same way, but I'm aware that proficient Haskell programmers don't tend to agree. How do you rate your Haskell skills? I've heard the same said of another 'weird and wonderful' language: Forth. Yes, it's incomprehensible if you aren't familiar with the language, but that's not really who the language is for.
- dleslie 6y agoI wrote a fair bit of Haskell about a decade ago; I'd rate myself a novice still, but I'm confident that I could knock out some games in a game jam using Haskell. I'm surprised no one has plugged Hoogle. It was the hands-down best resource to make Haskell reasonable for me. But even still, I found code that I wrote in Haskell not unlike the plentiful amount of code I wrote in Perl: returning to it after the fact was tedious.