Suppose I have the following data structure defined in my haskell code
data Exp = Expnum Int - constant
| Expplus Exp Exp - addition
data Pair = Pnum Int
| Plus Pair Pair
I would like to write a function that can convert the expression to following:
-- Example: (Expplus (Expplus (Enum 5) (Enum 5)) Enum 6)
-- equivalent to ((5+5)+6)
convert :: Exp -> Pair
...
-- Expected output: Plus (Pnum 5 (Plus (Pnum 5) (Pnum 6))
-- equivalent to (5+(5+6))
If here the expected entry is Plus((Plus (Pnum 5) (Pnum 5)) (Pnum 6)
I will have no problem writing a function like this.
However, I have no idea how can I write a recursion that starts with the final term, while when I parse in the expression it will be (Expplus (Enum 5) (Enum 5))
that is evaluated first and being returned back
First let's fix the definitions (syntax for comment wrong and I want to see the result so Pair
needs to be in Show
), and your exampel:
data Exp = Expnum Int
| Expplus Exp Exp
data Pair = Pnum Int
| Plus Pair Pair
deriving (Show)
example :: Exp
example = Expplus (Expplus (Expnum 5) (Expnum 5)) (Expnum 6)
now the idea is to first flatten the Exp
or if you like to extract the numbers in there:
extractConstants :: Exp -> [Int]
extractConstants (Expnum n) = [n]
extractConstants (Expplus a b) = extractConstants a ++ extractConstants b
this yields
> extractConstants example
[5,5,6]
the next step is to build from this list your final Pair
:
buildPair :: [Int] -> Pair
buildPair xs = foldr1 Plus $ map Pnum xs
so first we add wrap each number in a Pnum
and then just foldr1
using Plus
- you can eta-reduce the xs
here (see bellow).
note that this is not matching on []
- it will not matter but you should not have this on the top-level IMO - we'll fix that later
this one gives for the list the desired result:
> buildPair [5,5,6]
Plus (Pnum 5) (Plus (Pnum 5) (Pnum 6))
so all that is left is to combine those two:
convert :: Exp -> Pair
convert = buildPair . extractConstants
and that's it:
> convert example
Plus (Pnum 5) (Plus (Pnum 5) (Pnum 6))
now the issue with the missing case is left - if you think about it it will never happen for a list resulting form extractConstants
(there can be no empty-list here as there is no way to express this with Exp
. In this case I'd put at least this helper function as a where
- here I choose to do both:
convert :: Exp -> Pair
convert = buildPair . extractConstants
where
extractConstants (Expnum n) = [n]
extractConstants (Expplus a b) = extractConstants a ++ extractConstants b
buildPair = foldr1 Plus . map Pnum
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.