haskell - 类型 - 函数 - 树

时间:2011-05-18 18:46:31

标签: haskell types tree

对于haskell练习,我想实现一个游戏,学生/学生应该开玩笑地学习代数。

作为基本数据类型,我想使用树:

  • 包含存储标签和代数运算符的节点。
  • 带有标签和变量(类型为String)或数字
  • 的叶子

现在我要定义类似

的内容
data Tree = Leaf {l :: Label, val :: Expression}
          | Node {l :: Label, f :: Fun, lBranch :: Tree, rBranch :: Tree}

data Fun = "one of [(+),(*),(-),(/),(^)]"

-- type Fun = Int -> Int 

会起作用

接下来我想到的是制作树的“等价” - 因为乘法/加法是可交换的,并且可以简化乘法等的加法,以及整组代数运算。 我还必须在树上搜索 - 我认为最好的标签,这是一个很好的方法。

任何想法要查找的标签/短语以及如何解决“数据乐趣”。

2 个答案:

答案 0 :(得分:7)

对Edward Z. Yang的答案进行扩展:

在这里定义运算符的最简单方法可能是作为数据类型,以及叶节点中的原子值类型和表达式树的整体类型:

data Fun = Add | Mul | Sub | Div | Exp deriving (Eq, Ord, Show)

data Val a = Lit a | Var String deriving (Eq, Ord, Show)

data ExprTree a = Node String Fun (ExprTree a) (ExprTree a)
                | Leaf String (Val a)
    deriving (Eq, Ord, Show)

然后,您可以将ExprTree a定义为Num和以下内容的实例:

instance (Num a) => Num (ExprTree a) where
    (+) = Node "" Add
    (*) = Node "" Mul
    (-) = Node "" Sub
    negate = Node "" Sub 0
    fromInteger = Leaf "" . Lit

...允许以非常自然的方式创建未标记的表达式:

*Main> :t 2 + 2
2 + 2 :: (Num t) => t
*Main> 2 + 2 :: ExprTree Int
Node "" Add (Leaf "" (Lit 2)) (Leaf "" (Lit 2))

另请注意上面有关数据定义的deriving条款,尤其是Ord;这告诉编译器自动在该类型的值上创建排序关系。这使您可以对它们进行一致排序,这意味着您可以在子表达式上定义规范排序,以便在重新排列交换操作时不会陷入循环。给定规范顺序中的一些规范缩减和子表达式,在大多数情况下,您将能够使用Eq给出的自动相等关系来检查子表达式等价。

请注意,标签会影响此处的排序和相等性。如果不需要,您需要为EqOrd编写自己的定义,就像我为Num提供的定义一样。

之后,您可以编写一些遍历和缩减函数,以执行诸如应用运算符,执行变量替换等操作。

答案 1 :(得分:3)

看起来你想构建一个符号代数系统。关于这个主题有大量不同的文献。

您不希望将运算符表示为Int -> Int,因为您无法检查任何给定函数实现的操作,然后实现简化等事情的窥孔优化。因此,简单的枚举数据类型将做这个技巧,然后编写实际评估你的树的函数eval