First Class Statements
blog.jle.im
blog.jle.im
Traditional assignment is an expression in Haskell.
count :: Int -> IO Int
count n = do r <- newIORef 0
loop r 1
where
loop :: IORef Int -> Int -> IO Int
loop r i | i>n = readIORef r
| otherwise = do v <- readIORef r
writeIORef r (v+i)
loop r (i+1)You can take a list of IO actions ("statements") and use the sequence function to get a single statement out.
sequence :: Monad m => [m a] -> m [a]
Then you can execute the result by having it in the flow of your program, or pass it around just like any other statement.The list of statements can be put together however you like.
I'm not sure I understand. In Haskell, you can programmatically put statements together. You can't execute them willy-nilly just like how you can't try to execute an integer in python. You just create make a statement called "main" and the program is compiled so as to execute that statement.
(do-something-with '(+ a b))
and do-something-with could do any arbitrary transformation on the AST, possibly ending up passing it to eval, possibly optimizing it and compiling it to some other language... while Haskell's a leap in this regard compared to imperative languages, I think only something like Lisp can call its code truly first-class.First, directly addressing the question you asked:
There are a number of libraries for assembling and manipulating a Haskell AST - I would recommend looking at haskell-src-exts and Template Haskell. Unfortunately, there doesn't seem to be a way to exec any of these directly (at runtime). You could obviously pretty-print and then eval that, which may or may not be a good fit depending on your problem space.
Separately, I would like to suggest a different perspective, in line with the thesis of the article.
(Pardon me if this gets a bit rambly, and feel more than free to ask questions if it gets confusing - I've been meaning to expand on this in a blog post...)
Haskellers are fond of monads. Lispers are fond of S-expressions. Lisp programs are S-expressions. S-expressions are either an atom, or a list of S-expressions - a structure also known as a "rose tree".
It turns out, a rose tree is a monad. In particular, a "free monad", which means there's a unique function turning a rose tree into any other monad in a way that preserves structure (in math terms, a "monad homomorphism"). Getting slightly speculative, I think the homomorphism from Free to IO has to be Lisp's eval.
So in a senes, when Haskellers write functions that operate on "Monad m", they are writing functions that can operate on Lisp programs, and also on many "partial interpretations" or "restricted forms" of Lisp programs. This is why Haskell programmers get about as excited about monads as Lisp programmers do about macros - there's a deep connection.
The big thing that Haskell lacks, in this context, is a mutable global namespace - which keeps a few things compile-time only (and hence the need for Template Haskell for fuller coverage of metaprogramming).
AttributeError: 'int' object has no attribute '__call__'
I mean, of course it doesn't, that's what I'm trying to fix.At one point, I was desirous of having floating point numbers whose value decayed toward zero each time the number was accessed; you can achieve this by defining a custom class and implementing all the methods needed to make it behave like a float, but it's not the same.