Realizing Hackett, a metaprogrammable Haskell
lexi-lambda.github.io
lexi-lambda.github.io
If Haskell's Template Haskell + cross compilation woes can be avoided (ideally cross compilation should be as easy as in Go's tool chain), while retaining all the other goodies, I'll have a new favorite programming language!
https://github.com/combinatorylogic/mbase/blob/master/readme...
Really excited about this project!
"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?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.
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.
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.
(define myfunc length
#:type (-> [a] Int))
(define main
#:type (IO ())
(do (print (length "foo"))))Do they work as a replacement for newlines, which are ignored? It looks a bit like C's semi-colons, except twice as bad.
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.
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.
This page has some useful information about phases: https://docs.racket-lang.org/guide/phases.html
1) Debugging generated code can be a pain. To some degree this is true of most macro systems, but it certainly applies here.
2) It adds to build times, sometimes significantly.
3) There is an issue preventing use of Template Haskell when cross compiling.
Some other things of note:
The Haskell syntax is really complicated, compared to s-exprs. This is not entirely negative - variated syntax can help you know where you are in an expression and give more guidance when you mix things up - but it's not entirely positive either.
The stage restriction prevents using a piece of Template Haskell in the same module where you define it. For a lot of use cases, this doesn't matter... but it makes module-specific one-offs more awkward, moving their definition away from where they're relevant.
As of comparatively recent, there is "Typed Template Haskell". As originally conceived, Template Haskell generating an expression didn't "have to" produce an expression of the right type. Compilation would still fail once the type mismatch was detected, but further from the cause of the error.
To learn, not about racket, but about the point of macros. It seems to have worked. I was going for something along the lines of Cunninghams law.
Anyway, thanks for the insight on macros.
I would go further: a typed language needs the sort of metaprogramming macros provide to avoid having too much boilerplate and noise. You can either do this with a simple, general macro system or with ad-hoc features addressing narrow usecases a macro system would cover. Haskell's deriving mechanism, record system and syntax sugar like do-notation are all great examples of things that would be obviated with a solid macro system, making the language simpler.