5

It... kinda works you guys (This absolutely compiles, adapted from https://hackage.haskell.org/package/scotty):

main :: IO ()
main = (do
  (putStrLn "Starting Server....")
  (scotty 3000 (do
    (get "/hello/:name"
        (text ("hello " <> (param "name") <> "!")))

    (get "/users"
      (json allUsers))

    (get "/users/:id"
      (json (filter (matchesId (param "id")) allUsers))))))

(I don't know enough haskell to convert <> to simple parens, but a clever person could easily.)

Why would we do this? We could preprocess Haskell with any lisp macro engine! Trivially!.

Imagine it. HASKELL AND LISP TOGETHER. WE COULD RULE THE GALAXY!

enter image description here

(I know what your thinking, but I've actually thought this through: in this example, Vader is Lisp, Luke is Haskell, and Yoda is Alonzo Church)

(edit "Thanks everyone who answered and commented, I'm now much wiser. The biggest problem with this technique I don't think has been yet mentioned, and was pointed out by a friend IRL: If you write some lispy preprocessor, you lose type checking and syntax highlighting and comprehension in your IDE and tools. That sound like a hard pass from me."

"I'm now following the https://github.com/finkel-lang/finkel project, which is the lisp-flavoured haskell project that I want!")

0atman
  • 3,298
  • 4
  • 30
  • 46
  • 1
    Because *Lisp* uses way too much brackets, making it very unreadable. – Willem Van Onsem Feb 29 '20 at 10:42
  • That must explain its longevity! – 0atman Feb 29 '20 at 10:43
  • To be more serious, compare template haskell to lisp macros, and you see my motivation. – 0atman Feb 29 '20 at 10:45
  • 1
    /rant (1) All languages could be expressed in Lisp notations, but people have different tastes. Personally I find Haskell to be unreadable, I strongly prefer words over Perlisms, and prefer not to have to remember which operator has precedence over others, but that's not what haskell favors (see Arrow syntax, combinators, etc.). Visually speaking I would prefer if Haskell went full Unicode and used existing math operators, like APL. (2) Haskell users do not seem to value metaprogramming much, from what I see. – coredump Feb 29 '20 at 14:06
  • 2
    Here's an experiment in writing a Haskell-like language in Racket: https://github.com/lexi-lambda/hackett – danidiaz Feb 29 '20 at 14:27
  • 1
    @coredump while most languages can be written in a lisp style, see my example - haskell can be written EXACTLY like lisp! (at least expressions can seem to be). I'm with you on the pearl-like line noise. I am fantasising about a library that redefines all the symbols ($ & >>>) as words – 0atman Feb 29 '20 at 15:12
  • 3
    I'm not sure it actually buys you very much. Your macro will still have to know about all the special syntactic forms -- you don't want to run the same recursive operation on syntax bits that are patterns vs. syntax bits that are expressions, for example, so you can't just write a macro that works uniformly over the bits of a transformed `let` expression -- so the uniform serialization to text doesn't actually help. – Daniel Wagner Feb 29 '20 at 15:45
  • 2
    You can go too far with using words alone (cf. Python); trying to add a new feature becomes an adventure in trying to reuse existing keywords as much as possible (to avoid breaking code that assumed a word was available as an identifier) in a way that doesn't produce ambiguities with existing uses of the keyword. Symbols have their places; neither underusing nor overusing them is the right answer. – chepner Feb 29 '20 at 16:25
  • @chepner "reusing keywords" : don't namespace/modules/packages solve this? – coredump Feb 29 '20 at 17:17
  • That wasn't a great example, as Python is actually reserving words, rather than just having a library using an identifier for a new function. – chepner Feb 29 '20 at 17:19
  • Fair. But Plenty of builtins in python get clobbered accidentally by accident, see input() – 0atman Feb 29 '20 at 17:58
  • @coredump yet for some strange reason the advance in maths came when more and more [symbols have replaced the words](https://twitter.com/edsouthall/status/1231136957662670849). :) – Will Ness Feb 29 '20 at 21:54
  • 1
    Yeah but please note that linked graph has no axe, it is a wall of text with a curve :) – coredump Mar 01 '20 at 07:19
  • 1
    I'm a bit sad not to hear from [Alexis King](https://stackoverflow.com/users/465378/alexis-king) on this one. – dfeuer Mar 05 '20 at 05:03
  • @dfeuer same, I'd be also keen to hear Alexis's thoughts on https://github.com/finkel-lang/finkel – 0atman Mar 05 '20 at 09:12

3 Answers3

8

The syntax of Haskell is historically derived from that of ISWIM, a language which appeared not much later than LISP and which is described in Peter J. Landin's 1966 article The Next 700 Programming Languages.

Section 6 is devoted to the relationship with LISP:

ISWIM can be looked on as an attempt to deliver LISP from its eponymous commitment to lists, its reputation for hand-to-mouth storage allocation, the hardware dependent flavor of its pedagogy, its heavy bracketing, and its compromises with tradition.

Later in the same section:

The textual appearance of ISWIM is not like LISP's S-expressions. It is nearer to LISP's M-expressions (which constitute an informal language used as an intermediate result in hand-preparing LISP programs). ISWIM has the following additional features: [...]

So there was the explicit intention of diverging from LISP syntax, or from S-expressions at least.

danidiaz
  • 26,936
  • 4
  • 45
  • 95
  • Fascinating! And yet, as in my example, compatibility seems to remain? – 0atman Feb 29 '20 at 15:06
  • 3
    @0atman You can write quite bracketed Haskell (I often prefer using explicit brackets over the `$` operator) but the similarity is a bit deceiving, as the brackets don't really denote lists in the language, and you can't directly assemble code with lists and atoms, you need the Template Haskell AST. Incidentally, the non-operator version of `<>` is `mappend`, and `mconcat` combines a whole list of items. – danidiaz Feb 29 '20 at 15:20
6

Structurally, a Haskell program consists of a set of modules. Each module consists of a set of declarations. Modules and declarations are inert - they cause nothing to happen by their existence alone. They just form entries in a static namespace that the compiler uses to resolve names while generating code.

As an aside, you might quibble about Main.main here. As the entry point, it is run merely for being defined. That's fair. But every other declaration is only used in code generation if it is required by Main.main, rather than just because it exists.

In contrast, Lisps are much more dynamic systems. A Lisp program consists of a sequence of s-expressions that are executed in order. Each one causes code execution with arbitrary side effects, including modification of the global namespace.

Here's where things get a lot more opinion-based. I'd argue that Lisp's dynamic structure is closely tied to the regularity of its syntax. A syntactic examination can't distinguish between s-expressions intended to add values to the global namespace and ones intended to be run for their side effects. Without a syntactic differentiation, it seems very awkward to add a semantic differentiation. So I'm arguing that there is a sense in which Lisp syntax is too regular to be used for a language with the strict semantic separations between different types of code in Haskell. Haskell's syntax, by contrast, provides syntactic distinctions to match the semantic distinctions.

Carl
  • 26,500
  • 4
  • 65
  • 86
  • by adding to global namespace you mean lambdas at the top level of an s-expr? – X10D Apr 22 '20 at 01:27
  • @X10D I mean things like `defun` or `define`, depending on your specific Lisp. They insert values into the global namespace when they're executed. – Carl Apr 22 '20 at 04:37
3
  1. Haskell does not have s-exp so parentheses are only used for marking the precedence of reduction and constructing tuples, this also means that it's not that easy to make lisp like macros work in Haskell since they make heavy use of s-exps and dynamic typing
  2. Haskell has a right associative function application (namely ($)) which covers most use cases of parentheses
  3. Whitespaces has semantic meaning in Haskell, that's why most of us write
do
  p1
  p2
  p3

instead of

do { p1
   ; p2
   ; p3
   }
Poscat
  • 565
  • 3
  • 15