5

使用递归方案库,可以轻松编写抽象语法树和相应的表达式评估器:

{-# 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 

现在看一下algwhere 子句中函数中的 case eval。我认为所有的xy变量都不应该是必要的。因此,我正在寻找某种方法(语法、语言扩展等)来删除这个样板,然后写:

  PlusF  -> (+)
  MultF  -> (*)
  ConstF -> id 
4

2 回答 2

3

https://hackage.haskell.org/package/catamorphism-0.5.1.0/docs/Data-Morphism-Cata.htmlExprF.

{-# 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、 产生eval = expr (+) (*) id并让您跳过Data.Functor.Foldable.TH此特定用例的变态。

于 2018-02-03T19:25:34.503 回答
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
于 2018-02-09T15:24:04.677 回答