我正在为haskell中的各种函数调用构建一个优化器,这是我的AST
data Expr = ExprCall { _fname :: Text, _fparams :: [Expr] }
| ExprVar { _var :: Text }
| ExprNat { _nat :: Int }
Run Code Online (Sandbox Code Playgroud)
这里是语法的例子,mod并且random是外部函数和它们的语义是不透明的哈斯克尔.
mod(random(), 10)
Run Code Online (Sandbox Code Playgroud)
所有它都是语法的AST表示,对于上面的示例,它将是:
ExprCall "mod" [ExprCall "random" [], ExprNat 10]
Run Code Online (Sandbox Code Playgroud)
我有很多类型的传递,Expr->Expr我有一个函数调用descend它遍历AST并对每个传递一个传递Expr.这是我的下降功能
{- # LANGUAGE RecordWildCards #-}
descend :: (Expr -> Expr) -> Expr -> Expr
descend f ExprCall { .. } = ExprCall _fname $ map f _fparams
-- Base expressions
descend f other = f other
Run Code Online (Sandbox Code Playgroud)
现在,我意识到这是exacatly什么Data.Traversable呢,我想使我的expr的是一个实例,然而,在层次结构中所有类型类Functor,Foldable,Traversable等只接受两种* -> *.为什么?
有什么方法可以让我Expr做到这(* -> *)一点,这在逻辑上是有道理的吗?或者,有没有办法让单形可穿越?
data Expr a与我相比,声明数据有什么好处data Expr?
这些类的多态性有一些好处:类型更具描述性,并且可以防止某些实现错误。
这两个优点的主要原因是多态类型的实现通常比更专门的类型少得多。如果我们排除异常和无限循环,实际上只有两种方法来实现fmap :: (a -> b) -> Maybe a -> Maybe b,并且一种是常量函数,因此只有另一种才是真正明智的:
fmap f (Just a) = Just (f a)
fmap f Nothing = Nothing
-- or
fmap f (Just _) = Nothing
fmap f Nothing = Nothing
Run Code Online (Sandbox Code Playgroud)
相比之下,从(Int -> Int) -> Maybe Int -> Maybe Int技术上讲,该类型很少告诉我们此类函数的作用。特别是,人们可能会忘记使用第一个参数,在我看来,这并不是一个牵强的错误:
fmap :: (Int -> Int) -> Maybe Int -> Maybe Int
fmap f (Just a) = Just a
fmap f Nothing = Nothing
Run Code Online (Sandbox Code Playgroud)