简体   繁体   中英

Defining a normal form with Haskell

I'm trying to get an expression and turn it into a standard form. To better clarify my purpose, assume you define a general style for your expressions like this:

∑(a*b) // sum of products

Now if you're given an input which is not in that format like: (a+b)*(c+d), you'll need to normalize it first.(Actually it is only a simple example and not my case) Now I have a code which is already written in ML and it's too long. Here you can see some snipets:

rew(p_choice(x,p_nil)) = rew(x) |
rew(p_choice(p_nil,x)) = rew(x) |
rew(p_sum(d,p_nil)) = p_nil |
rew(p_sum(d,p_choice(x,y))) = rew(p_choice(rew(p_sum(d,x)),rew(p_sum(d,y)))) 
rew(p_cond(b,p_nil,p_nil)) = p_nil |
rew(p_cond(b,p_choice(x,y),p_nil)) =rew(p_choice(rew(p_cond(b,x,p_nil)),rew(p_cond(b,y,p_nil)))) |
rew(p_cond(b,p_sum(x,y),p_nil)) = rew(p_sum(x,rew(p_cond(b,y,p_nil)))) |
rew(p_cond(b1,p_cond(b2,x,p_nil),p_nil)) = rew(p_cond(b1 andalso b2, x,p_nil)) |
rew(p_cond(b,x,p_nil)) = p_cond(b,x,p_nil) |
rew(p_cond(b,x,y)) =
    rew(p_choice(rew(p_cond(b,x,p_nil)),rew(p_cond(not(b),y,p_nil)))) 

My question is, does Haskell introduce any features that can help this code be done more neatly?

The pattern matching facilities in Haskell are very similar and I don't think the biggest Haskell exclusivities (typeclasses, lazyness, etc) are going to help you. That said, there might be ways to make things simpler in ML.

One thing to consider is to divide the processing in smaller steps. Right now there is some duplication depending if things are the left or the right argument. You could try transforming to an intermediate standard form that chooses one particular order for things.

Another trick is separating the processing of each step from the recursion so you don't mix the tree traversal with the node processing. You can write functions to process the stp for each node and then you use a separate fold function to tie everything together.

data Tree = Leaf Int | Node Tree Tree

directsum :: Tree -> Int
directSum (Leaf n) = n
directsum (Node a b) = (directsum a) + (directsum b)

-- vs

foldtree :: (Int -> r) -> (r -> r -> r) -> Tree  -> b
foldtree onLeaf onNode t =
    go t
  where
    go (Leaf n)   = onLeaf n
    go (Tree a b) = onNode (go a) (go b)

foldedSum :: Tree -> Int
foldedsum t =
    foldtree leafsum nodesum t
  where
    leafsum n = n
    nodesum a b = a + b

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM