使用haskell中的let绑定的算术表达式的数据类型

时间:2016-04-04 23:00:16

标签: haskell

使用haskell中的let绑定的算术表达式的数据类型

1 个答案:

答案 0 :(得分:0)

这是原始Expr类型的变体,它添加了变量(V)并允许绑定(Let)。

data Expr = C Float | V String
          | Let [(String, Expr)] Expr
          | Expr :+ Expr | Expr :- Expr
          | Expr :* Expr | Expr :/ Expr

为了帮助编写evaluate,您可能希望从一个执行变量替换的函数开始:

data Expr = C Float | V String
          | Let [(String, Expr)] Expr
          | Expr :+ Expr | Expr :- Expr
          | Expr :* Expr | Expr :/ Expr
            deriving Show

-- | @sub var value e@ replaces variables named @var@ with the value @value@
-- wherever anywhere that variable occurs in expression @e@.
sub :: String -> Expr -> Expr -> Expr

-- "let x = y in x" = y
sub v1 value (V v2) | v1 == v2 = value

-- "let x = y in z" = z
sub _ _ e@(V _) = e

-- Constants are unaffected
sub _ _ c@(C _) = c

-- For operators, apply @sub a b@ recursively to the operands.
sub a b (e1 :+ e2) = (sub a b e1) :+ (sub a b e2)
sub a b (e1 :- e2) = (sub a b e1) :- (sub a b e2)
sub a b (e1 :* e2) = (sub a b e1) :* (sub a b e2)
sub a b (e1 :/ e2) = (sub a b e1) :/ (sub a b e2)

-- The variable is shadowed by a let binding, so only substitute
-- into the bindings, and leave the body expression unmodified.
sub a b (Let bindings e) | bindingsContains a bindings =
    Let (subIntoBindings a b bindings) e

-- Apply @sub a b@ recursively to the body of the let expression.
sub a b (Let bindings body) =
    Let (subIntoBindings a b bindings) (sub a b body)

bindingsContains :: String -> [(String, Expr)] -> Bool
bindingsContains x bindings =
    Data.Maybe.isJust $ Data.List.find ((== x) . fst) bindings

subIntoBindings :: String -> Expr -> [(a, Expr)] -> [(a, Expr)]
subIntoBindings a b bindings = (fmap . fmap) (sub a b) bindings