
Realizing Hackett, a metaprogrammable Haskell - sndean
https://lexi-lambda.github.io/blog/2017/05/27/realizing-hackett-a-metaprogrammable-haskell/
======
kornish
This is awesome! I know lots of people would love the type safety of a Haskell
or OCaml combined with the metaprogramming and AST manipulation capabilities
of a Lisp - and that seems to be the eventual goal of this project.

~~~
mushiake
There is a proposal for new Ocaml macro inspired by racket.[0]

[0][http://www.lpw25.net/ocaml2015-abs1.pdf](http://www.lpw25.net/ocaml2015-abs1.pdf)

~~~
kornish
Very exciting - thanks for sharing. Now we just need proper multicore and
_that 's_ a versatile modern language.

------
Klasiaster
Nice to see Haskell and LISP ideas combined, that's inspiring and teaches the
advances of 'the other' if you know only one of them. For a Prolog and Haskell
marriage check out Curry:
[https://en.wikipedia.org/wiki/Curry_(programming_language)](https://en.wikipedia.org/wiki/Curry_\(programming_language\))

------
chickenfries
I just want to say that this post is well written, witty and I loved the
inclusion of what music they were listening to while working on Hackett.

------
TuringTest
(tongue-in-cheek

    
    
       "This is just what I wanted, all the syntactic peculiarities of Haskell with all the parentheses of Lisp." 'sarcasm.)
    

Is there a way that Hackett would standardize in using _Readable Lisp_ [1]
with Sweet-expressions as the default reader, to get rid of all the unneeded
parentheses?

[1] [http://readable.sourceforge.net/](http://readable.sourceforge.net/)

~~~
runeks
I'm curious, in which ways do you find Haskell syntax peculiar? Haskell has
some of the cleanest syntax I've ever seen, not the least because tabs and
newlines have meaning -- like in Python (which I also love).

I seem to harbor an unhealthy amount of hatred towards Lisp because of all the
parentheses. The example shown at your link makes me visibly upset, unless I'm
mentally prepared for it. I love the _$_ in Haskell, which lets me leave out
parentheses, and I never use more than single level of nested parentheses,
because the resulting code looks confusing to me.

~~~
TuringTest
I agree that Haskell syntax is incomparably clean, and that it works great for
the classic simple program structures. But this laconism often makes it
difficult to read.

I understand the power of point-free style, and it's quite exclusive to build
pipelines. But it is very hard to read a function in that style if you're not
already familiar with all the abstractions used.

The $ operator is a particular culprit ;-D Understanding a function depends
heavily on precedence of operators. This is easy to do with algebra, because
it uses few different operators. But in programming, where you have a huge
number of functions defined in the program, it may be very hard to start
reading a new program for the first time.

------
kovek
It seems to me like lisp-like (let's call this "somelisp", defined transpiled
using Racket) syntax can be easily transpiled to other languages.

If in Haskell I have for example:

    
    
        myFunc :: [a] -> Int
        myFunc = length
        main = do 
            print $ length "foo"
    

It seems like you could easy express this in "somelisp" with:

    
    
        (myFunc :: [] a -> Int)
        (myfunc = length)
        (main = do  
           print (length "foo"))
    

And since you're using lisp-like syntax, you have the possibility to use
macros now!

Now, I don't know if it would simply be simpler to encode these macros in your
"somelisp" language defined using Racket, if you should make a Haskell
extension, or if you should just not use it at all?

What about having macros defined in specific files, and use the target
language, say Haskell in your code, but whenever you want to use a macro, use
a syntax that Haskell does not accept: $(mymacro print $ length "foo") and
have a preprocessor convert this macro to its corresponding haskell code?

I am currently learning Haskell, so I don't know if there are more complex
examples where this will not work.

~~~
minikomi
You nerdsniped me. Just spitballing a more racket-like way to write it..

    
    
        (define myfunc length 
                #:type (-> [a] Int))
        (define main 
                #:type (IO ()) 
           (do (print (length "foo"))))

------
moomin
Whilst undoubtedly cool, and based on super-interesting research, it's worth
bearing in mind this is a compile-to-Racket language. Anyone who's used a
compile-to-JS language will be familiar with the drawbacks of this approach.

~~~
nickpsecurity
Will they be the same drawbacks given Racket is designed to be easier to
transform from there?

~~~
moomin
Pretty much. Take the example in the post: the web server is Racket's web
server with an FFI wrapper. So you're using an API that was never designed
with Hackett's type system in mind. So now you've got the choice between
exposing an efficient or an idiomatic interface. And so on...

------
nathell
Other Haskells with Lisp syntax:
[https://wiki.haskell.org/Haskell_Lisp](https://wiki.haskell.org/Haskell_Lisp)

------
amelius
I'm wondering how much "hacking" (e.g. use of undocumented functionality,
modifying of existing code) is required to bolt this on an existing Haskell
compiler.

------
rocqua
I'm probably wrong here, but I wonder. Why go outside the haskell type system,
but still use haskell.

As I see it, haskell is all about the type system, and macros are all about
circumventing the limits of the type system. These things seem at odds.

I have to admit I have no idea what racket is, nor did I do much more than
scan the article.

~~~
jonsterling
> I have to admit I have no idea what racket is, nor did I do much more than
> scan the article.

why have you commented then? Mao Zedong had a dope saying about this, "No
investigation, no right to speak!"

\-----------------------------

One answer to your questions, btw, is that macros are useful and interesting
regardless of what kind of type system you have. Haskell has something called
Template Haskell, which is really quite bad for a number of reasons, but it is
certainly possible to imagine a version of Haskell with a well-designed macro
system. It just so happens that Racket has an exceptionally well-designed
macro system, so the partnership of the two ideas is very plausible and
scientifically interesting.

Macros and types are _not_ in opposition. However, macros induce a notion of
PHASE which is not usually accounted for in type systems, though it may be
possible to account for this in a principled/type-theoretic way using ideas
from modal logic and kripke semantics.

~~~
julian_1
Could you explain what phase is? I understand haskell types, and I suspect
Template haskell mostly works as an AST translator. A Google search on macros
and phase, just turns up diet and bodybuilding preparation advice!

~~~
dbpatterson
In the simplest case, a macro system gives rise to two-phase evaluation -
first, there is code that runs at macro expansion time, that produces, as its
result, new syntax, and second, that resulting code runs. But having just two
phases is (needlessly) restrictive, because you might want macros that
generate other macros (and so the macro-generating macros would need to run at
an earlier phase than the generated ones).

~~~
chongli
Wouldn't the macro-expansion phase be run until it reaches a fixed point? That
way all macros could be fully expanded before proceeding to the next phase.

~~~
wtetzner
I believe that's how macros in Racket work, but each iteration is considered a
separate phase. At least, that's how I understood it.

This page has some useful information about phases: [https://docs.racket-
lang.org/guide/phases.html](https://docs.racket-lang.org/guide/phases.html)

