Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 将函数自动应用于子结构_Haskell_Recursion_Algebraic Data Types - Fatal编程技术网

Haskell 将函数自动应用于子结构

Haskell 将函数自动应用于子结构,haskell,recursion,algebraic-data-types,Haskell,Recursion,Algebraic Data Types,假设我正在抽象语法树数据类型上编写一个“替换”函数: data Term = Id String | If Term Term Term | Let String Term Term ... subst :: String -- name of identifier to replace -> Term -- term to replace the identifier with -> Term

假设我正在抽象语法树数据类型上编写一个“替换”函数:

data Term = Id String
          | If Term Term Term
          | Let String Term Term
          ...

subst :: String -- name of identifier to replace
      -> Term   -- term to replace the identifier with
      -> Term   -- body in which to perform the replacements
      -> Term
subst identifier term = go
  where go (Id id') = if identifier == id' then term else Id id'
        go (If t1 t2 t3) = If (go t1) (go t2) (go t3)
        go (Let id' term' body) = Let id' (go term') (go body)
        ...

(忽略阴影问题)。请注意编写
If
分支是多么乏味。我必须进行模式匹配,命名这3个部分,然后重构一个
If
go
明确应用于这3个部分中的每一个。对于
Let
,我必须进行模式匹配,命名这3个部分,并重构一个
Let
,将
go
明确应用于相关的2个部分。有没有一种更简单(无点?)的方法来编写它而不必详细说明每一个细节?

这里最好的方法是使用数据类型泛型编程,它正是为类似这样的任务而设计的。下面是一个使用标准库的示例:


这直接表示转换(在本例中,将函数
go
应用于
Term
类型的任何子级)应以自底向上的方式应用于整个树。这不仅更加简洁,而且只要基本递归方案保持不变,无论向
术语添加多少构造,相同的代码都会继续工作。

ehird回答了一般问题;您可能会发现更好地回答了特定问题,将第一行
go
简化为“
go(Id Id');identifier==Id'=term
”。
{-# LANGUAGE DeriveDataTypeable #-}

import Data.Generics

data Term = Id String
          | If Term Term Term
          | Let String Term Term
          deriving (Eq, Show, Typeable, Data)

subst :: String -- name of identifier to replace
      -> Term   -- term to replace the identifier with
      -> Term   -- body in which to perform the replacements
      -> Term
subst identifier term = everywhere (mkT go)
  where go (Id id') = if identifier == id' then term else Id id'
        go x = x