Karva notation is used in Gene Expression Programming to represent mathematical expressions.
See here http://www.gene-expression-programming.com/Tutorial002.asp
You create an expression tree by reading the off the gene and filling in nodes from left to right, top to bottom.
So for example using the operators ( +, * ) and terminals (1,2,3,4,5,6) in "+*+1+2*3456" would evaluate to 39.
How would I do this in haskell using attoparsec (or parsec)?
karvaParser :: Parser Int
karvaParser = ????????????
Prelude> parse karvaParser "+*+1+2*3456"
Done 39
(I've proved this is a linear time algorithm in this answer to the question mentioned in the comments. There's a lengthier more hand-rolled solution in a previous revision of this answer.)
Gene Expression Programming: Karva notation.
There's probably a neat solution using the continuation passing monad,
Cont, but I haven't thought of it. Here's a fairly clean pure functional solution to the problem. I'll take the opportunity to name drop some good general recursion schemes along the way.Plan:
split the input into lists, one for each layer, using the total arity of the previous line. This is an anamorphism, i.e. grows a list from a seed (
[]) and can be written usingunfoldr :: (b -> Maybe (a, b)) -> b -> [a]or equivalently,unfoldr' :: (b -> (a, b)) -> (b -> Bool)-> b -> [a]Recursively use
splitAtto glue the children under the parent. This is a catamorphism, i.e. collapses a list down to a single (tree) value, and can be written usingfoldr :: (a -> b -> b) -> b -> [a] -> bCombine the anamorphism and the catamorphism into one. That's called a hylomorphism. These terms are introduced to the FP community in the seminal paper Functional Programming with Bananas, Lenses and Barbed wire.
Code
In case you're not familiar with it,
Data.Treesuppliesdata Tree a = Node {rootLabel :: a, subForest :: Forest a}wheretype Forest a = [Tree a].To pull out a level, we use the total arity from the previous level to find where to split off this new level, and pass on the total arity for this one ready for next time:
To combine a level (as a String) with the level below (that's already a Forest), we just pull off the number of trees that each character needs.
Now we can parse the Karva using a hylomorphism. Note that we seed it with a total arity from outside the string of
1, since there's only one node at the root level. I've used theheadfunction because that1causes the top level to be a list containing one tree.Demo
Let's have a draw of the results (because Tree is so full of syntax it's hard to read the output!). You have to
cabal install pretty-treeto getData.Tree.Pretty.Which matches
as we see when we
seeit:Eval
Once you have a Tree, it's easy to convert it to other things. Let's evaluate an expression in Karva notation: