繁体   English   中英

在Haskell中组合函数

[英]Combining functions in Haskell

如何在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 (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)

Letter,Group,Star,Plus和Ques都是数据类型定义的一部分。

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]

在这个公式中,每个案例都有一个鉴别器字段,您可以用它区分每种情况的不同类型。 在这里,我只使用了String,假设你给它们命名为“Operand”,“Letter”,“Star”等等,但你也可以为各种Val ,各种UnOp的有效鉴别器定义单独的枚举类型,等等

在这种情况下你失去的主要是类型安全; 你可以用我给它们的String字段构造特别荒谬的东西。 解决这个问题的第一种方法是使用所谓的智能构造函数 ; 这些是具有特定类型参数的函数,这些参数以类型安全的方式构建更弱类型的核心数据。 只要您不从模块中导出实际的MyData构造函数,您的类型的其他用户将只能通过智能构造函数构建合理的数据。

如果您希望从类型构造函数本身获得更多安全构造的保证,您可能需要转向广义代数数据类型(GADT)幻像类型的概念 这些背后的基本思想是在数据类型定义的=左侧的类型变量与右侧的类型变量之间建立更灵活的关系。 然而,它们是Haskell的一个新的高级功能,所以你可能想要继续跳进它们,直到你牢牢掌握标准的Haskell数据类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM