Haskell:有没有更好的方法用相同的RHS编写案例语句?
例如:Haskell:有没有更好的方法用相同的RHS编写案例语句?,haskell,case,Haskell,Case,例如: data A = A B D | Aa B C | Ag B X X | Ae B R Q | Ax X getB a = case a of (A b _) -> b (Aa b _) -> b (Ag b _ _) -> b (Ae b _ _) -> b (Ax _) -> somethingElse 在Haskell中
data A =
A B D
| Aa B C
| Ag B X X
| Ae B R Q
| Ax X
getB a = case a of
(A b _) -> b
(Aa b _) -> b
(Ag b _ _) -> b
(Ae b _ _) -> b
(Ax _) -> somethingElse
在Haskell中,给定一个数据类型,其中许多构造函数具有相同的参数类型,是否有更好的方法返回此参数。或者有没有更好的方法来编写上面显示的
case
语句以减少重复?函数级的模式匹配将有助于提高可读性,但由于这些都是不同的构造函数,因此无法一次对多个构造函数进行模式匹配(据我所知)
如果
A
具有数据实例,则可以编写
import Data.Data
mgetB :: A -> Maybe B
mgetB = gmapQi 0 cast
然后根据这个函数定义getB,一个叫做“or patterns”的特性,在ML中可用,在这方面很有帮助。五年前GHC就有了这样一个功能,但似乎没有人承担起指定细节并实际实施的任务。然而,有一种方法可以用模板Haskell来做类似的事情,正如中所解释的那样,在某个时候,你必须说明你的
B
s是如何包含在a
中的,所以你最好用一种通用的方法一劳永逸地完成它
bOrX a = case a of
(A b _) -> B' b
(Aa b _) -> B' b
(Ag b _ _) -> B' b
(Ae b _ _) -> B' b
(Ax x) -> X' x
随后,您可以用很少的代码一次匹配所有B
s
getB a = case bOrX a of
B' b -> b
X' _ -> somethingElse
anotherFunctionWithBandX a = case bOrX a of
B' b -> f b
X' x -> g x
您可以使用和中的来简化此操作:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
-- ...
data A =
A { _b :: B, _d :: D }
| Aa { _b :: B, _c :: C }
| Ag { _b :: B, _x1 :: X, _x2 :: X }
| Ae { _b :: B, _r :: R, _q :: Q }
| Ax { _x1 :: X }
makeLenses ''A
getB :: A -> B
getB a = case a ^? b of
Just theB -> theB
Nothing -> somethingElse
对模板Haskell函数的调用makelens
处理所有样板文件
<代码>晶状体< /代码>如果您只使用它,可能会有点依赖性,但这是值得考虑的(尤其是如果您已经使用<代码>晶状体< /代码> /考虑使用<代码>晶状体< /代码>)。
您可以使用记录语法来绕过这个:data A =
A {fieldB :: B, fieldC :: C} |
Aa {fieldB :: B, fieldX1 :: X, fieldX2 :: X} |
Ag {fieldB :: B, fieldR :: R, fieldQ :: Q} |
Ax {fieldX :: X}
getB a = case a of
Ax -> somethingElse
_ -> fieldB a
关键是要给
B
类型的所有字段赋予相同的名称。这些构造器中的b
之间没有基本的相关性;它们只是巧合地被标记为相同的东西。Related:Related:命名非记录类型字段的形式通常不好吗?有可能只做全部吗?@dfeuer我不知道你所说的“非记录类型”是什么意思,但是如果这些字段只是通过镜头
函数访问的,那么一切都应该保持良好和全面。您可以通过不导出带下划线的名称来实现这一点。这与David Young的回答类似,只是没有添加镜头
层。我的观点是,您不需要模板Haskell和大型复杂库。这只是记录语法。是的,这是重点。我想我只是觉得提到这两个答案之间的关系是有意义的,因为它们基于同一个概念。我把这个作为答案,因为这是我处理这个问题的实际方法,但是有很多好的答案,我学到了很多。所以,感谢所有的答案,伙计们:)
data A =
A {fieldB :: B, fieldC :: C} |
Aa {fieldB :: B, fieldX1 :: X, fieldX2 :: X} |
Ag {fieldB :: B, fieldR :: R, fieldQ :: Q} |
Ax {fieldX :: X}
getB a = case a of
Ax -> somethingElse
_ -> fieldB a