如何在用递归方案编写的表达式求值程序中编写更少的样板文件

时间:2018-02-03 17:43:30

标签: haskell syntax boilerplate recursion-schemes

使用{{3}}库 编写抽象语法树和相应的表达式赋值器很容易:

PING 109.236.87.141 (109.236.87.141): 56 data bytes
ping: sending packet: Network is unreachable

现在看一下{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE LambdaCase #-} import Data.Functor.Foldable import Data.Functor.Foldable.TH data Expr = Plus Expr Expr | Mult Expr Expr | Const Expr deriving (Show, Eq) makeBaseFunctor ''Expr -- Write a simple evaluator eval :: Expr -> Int eval = cata alg where alg = \case PlusF x y -> (+) x y MultF x y -> (*) x y ConstF x -> x 的where子句中alg函数的情况。我认为所有evalx变量 不应该是必要的。因此,我正在寻找某种方式(语法,语言扩展等) 删除此样板并只写:

y

2 个答案:

答案 0 :(得分:3)

https://hackage.haskell.org/package/catamorphism-0.5.1.0/docs/Data-Morphism-Cata.html导致ExprF的变形。

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveFunctor #-} 
{-# LANGUAGE DeriveFoldable #-} 
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE TemplateHaskell #-}

import Data.Functor.Foldable 
import Data.Functor.Foldable.TH
import Data.Morphism.Cata

data Expr 
  = Plus Expr Expr 
  | Mult Expr Expr 
  | Const Expr 
  deriving (Show, Eq)
makeBaseFunctor ''Expr
$(makeCata defaultOptions ''ExprF)

-- Write a simple evaluator
eval :: Expr -> Int 
eval = cata $ exprF (+) (*) id

请注意,它还可以为Expr派生一个catamorphism,产生eval = expr (+) (*) id并让您跳过Data.Functor.Foldable.TH这个特定的用例。

答案 1 :(得分:1)

或者,您可以重构您的语言,一方面进行二元操作,另一方面进行一元化操作。你写的是:

data BinOp = PlusOp | MultOp deriving (Show, Eq)
data UnOp  = ConstOp deriving (Show, Eq)

data Expr  = Bin BinOp Expr  Expr
           | Un  UnOp  Expr
         deriving (Show, Eq)
makeBaseFunctor ''Expr

评估员随后成为:

eval :: Expr -> Int
eval = cata $ \case
  BinF op l r -> bin op l r
  UnF  op v   -> un op v
  where
    bin = \case
      PlusOp -> (+)
      MultOp -> (*)

    un = \case
      ConstOp -> id