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

Jog*_*ger 5 syntax haskell boilerplate recursion-schemes

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

{-# 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 
Run Code Online (Sandbox Code Playgroud)

现在看看algwhere子句中函数的情况eval.我认为所有xy变量都不是必需的.因此,我正在寻找一些方法(语法,语言扩展等)来删除这个样板并只写:

  PlusF  -> (+)
  MultF  -> (*)
  ConstF -> id 
Run Code Online (Sandbox Code Playgroud)

gal*_*ais 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
Run Code Online (Sandbox Code Playgroud)

评估者则变为:

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
Run Code Online (Sandbox Code Playgroud)