Haskell树与功能分支

时间:2014-07-03 17:54:41

标签: list function haskell

我首先要说的是我对Haskell很新,所以我还没有学过像Monads这样的东西。

在Haskell中,我正在尝试创建一种树,其中数字作为叶子,并且作为分支起作用,因此整个树可以像计算器一样。

到目前为止,这是我的代码。目前我没有将功能作为输入,而只是使用字符。

data Tree3 = Leaf3 Int | Node3 Char Tree3 Tree3 deriving (Show)
-- I would like to replace this ^  Char somehow with a function.

evaluate :: Tree3 -> Int
evaluate (Leaf3 x) = x
evaluate (Node3 c m n) | c == '+'    = evaluate m + evaluate n
                       | c == '-'    = evaluate m - evaluate n
                       | c == '/'    = evaluate m `div` evaluate n
                       | c == '*'    = evaluate m * evaluate n

所以我的问题是我可以在数据结构中输入一个函数(该类型是什么?)

对于可能令人困惑的问题感到抱歉,但感谢您的任何建议!

1 个答案:

答案 0 :(得分:5)

我建议你把树写成:

data Tree = Leaf Int | Node (Int -> Int -> Int) Tree Tree

请注意,您无法派生EqShow,因为Int -> Int没有实现其中任何一个类型类(并且它们都是不可能 不切实际这样做。)

然后您可以将evaluate功能编写为

evaluate :: Tree -> Int
evaluate (Leaf x) = x
evaluate (Node f l r) = f (evaluate l) (evaluate r)

这简单得多!

您可以创建一个树来表示像(1 + 2) * (3 * 4)这样的表达式

expr :: Tree
expr = Node (*) (Node (+) (Leaf 1) (Leaf 2)) (Node (*) (Leaf 3) (Leaf 4))

另一种方法可以让你更容易打印你的树,那就是使用几乎相同的定义:

data Tree = Leaf Int | Node String Tree Tree
--                          ^ String instead of Char

然后,如果您导入了Data.Map,则可以创建要查找的函数映射,但这会使您的evaluate函数更复杂,因为您介绍了函数获胜的可能性&#39 ;在你的地图上。幸运的是,Haskell有一些非常方便的工具可以优雅地处理它!

import qualified Data.Map as Map

type Tree = Leaf Int | Node String Tree Tree deriving (Eq, Show)

type FuncMap = Map.Map String (Int -> Int -> Int)

evaluate :: FuncMap -> Tree -> Maybe Tree
evaluate funcs (Leaf x) = return x
evaluate funcs (Node funcName left right) = do
    -- Use qualified import since there's a Prelude.lookup
    f <- Map.lookup funcName funcs
    l <- evaluate funcs left
    r <- evaluate funcs right
    return $ f l r

如果尝试类似

,这将自动生成Nothing
evaluate (Map.fromList [("+", (+))]) (Node "blah" (Leaf 1) (Leaf 2))

因为"blah"中的函数FuncMap不存在。请注意,由于Maybe的monad实例,我们无法进行任何类型的显式错误处理!如果函数映射的任何查找返回Nothing,则整个计算返回Nothing,而我们不必考虑它。