Function Haskell中的组合函数
如何在Haskell中组合这些类似的函数Function Haskell中的组合函数,function,haskell,functional-programming,Function,Haskell,Functional Programming,如何在Haskell中组合这些类似的函数 getGroup [] acc = reverse acc getGroup ((Letter x):letfs) acc = getGroup letfs ((Letter x):acc) getGroup ((Group x):letfs) acc = getGroup letfs ((Group (makeList x)):acc) getGroup ((Star x):letfs) acc = getGroup letfs ((Star (mak
getGroup [] acc = reverse acc
getGroup ((Letter x):letfs) acc = getGroup letfs ((Letter x):acc)
getGroup ((Group x):letfs) acc = getGroup letfs ((Group (makeList x)):acc)
getGroup ((Star x):letfs) acc = getGroup letfs ((Star (makeList x)):acc)
getGroup ((Plus x):letfs) acc = getGroup letfs ((Plus (makeList x)):acc)
getGroup ((Ques x):letfs) acc = getGroup letfs ((Ques (makeList x)):acc)
字母、组、星形、加号和QUE都是数据类型定义的一部分
data MyData a
= Operand a
| Letter a
| Star [RegEx a]
| Plus [RegEx a]
| Ques [RegEx a]
| Pipe [RegEx a] [RegEx a]
| Group [RegEx a]
deriving Show
我想知道是否有更好的方法来编写这些函数,因为它们具有相似性。
大多数情况下,我希望组合Group、Star、Plus和Ques的函数,因为它们是相同的,但如果有一种方法可以组合所有这些函数,那就更好了。如果不使用模板Haskell,就无法摆脱模式匹配的重复,这可能不值得只使用五个不同的构造函数。不过,您可以消除许多其他重复,并改进函数的性能特征
getGroup = map go
where go (Letter x) = Letter x
go (Group x) = Group . makeList $ x
go (Star x) = Star . makeList $ x
go (Plus x) = Plus . makeList $ x
go (Ques x) = Ques . makeList $ x
除了更加简洁之外,它还消除了尾部递归,这种递归在Haskell这样的惰性语言中会导致空间泄漏。当您将数据类型定义为多个不同情况的不相交并集时,在处理这种类型的函数中,您将不可避免地遇到大量的案例分析 减少案例分析的一种方法是通过分解公共性来简化基本类型:
data MyData a = Val String a
| UnOp String [Regex a]
| BinOp String [Regex a] [Regex a]
在这个公式中,每个案例都有一个鉴别器字段,您可以用它来区分每个案例的不同类型。在这里,我只是使用字符串,假设您给它们命名,如“操作数”、“字母”、“星”等,但您也可以为Val
、UnOp等类型的有效鉴别器定义单独的枚举类型
在这种情况下,你失去的主要是类型安全;您可以使用我提供的字符串
字段来构造特别无意义的东西。解决这个问题的第一个方法是使用所谓的智能构造函数;这些函数具有特定类型的参数,可以以类型安全的方式构建更弱类型的核心数据。只要您不从模块中导出实际的MyData
构造函数,您类型的其他用户将只能通过您的智能构造函数构造合理的数据
如果您想从类型构造函数本身获得更多安全构造的保证,那么您应该转向广义代数数据类型(GADT)和幻象类型的概念。其基本思想是在数据类型定义的
=
左侧的类型变量和右侧的类型变量之间建立更灵活的关系。不过,它们是Haskell的一个新的高级功能,因此您可能希望在牢牢掌握标准Haskell数据类型之前不要使用它们。对不起。。。我是哈斯克尔的新手。因此,我的函数字母(例如)实际上将变成:go((字母x):lefts)acc=getGroup lefts((字母x):acc)
?不,去掉累加器。尾部递归在处理惰性求值时不好;它会导致空间泄漏。最好使用像map
这样的高阶函数,但是如果要使用显式递归,它应该是这样的getGroup((字母x):lefts)=字母x:getGroup lefts
。我得到了这个错误:解析输入错误go',这是在第二次执行时发生的:
getGroup=map go where go(字母x):lefts)=字母x:getGroup lefts go((星x):lefts)=(星x):getGroup lefts go((加x):lefts)=(加x):getGroup lefts go((加x):getGroup lefts go((问题x):lefts)=(问题x):getGroup lefts go((问题x):getGroup lefts go((问题x):getGroup lefts)=(问题x):getGroup lefts `(所以我认为第一个是可以的)。此外,使用显式递归似乎可以工作:D,但它仍然分为五个函数。尝试从回复中逐字复制答案并手动复制,应该可以工作。您的go
定义与答案中的定义不同。