我有一些很常见的Haskell样板,它出现在很多地方。它看起来像这样(实例化类时):
a <= b = (modify a) <= (modify b)
像这样(具有正常功能):
fn x y z = fn (foo x) (foo y) (foo z)
有时甚至是元组,如:
mod (x, y) = (alt x, alt y)
似乎应该有一种简单的方法来减少所有这些样板,而不必重复自己。 (这些都是简单的例子,但确实很烦人)。我想是为了删除这样的样板而创建的抽象,但我不确定它们被称为什么,也不知道在哪里看。任何haskellites可以指向我正确的方向吗?
答案 0 :(得分:12)
对于(<=)
案例,请考虑定义compare
;然后你可以使用Data.Ord.comparing,如下所示:
instance Ord Foo where
compare = comparing modify
请注意comparing
可以使用Data.Function.on简单地定义为comparing f = compare `on` f
。
对于您的fn
示例,目前尚不清楚。一般来说,没有办法简化这种类型的定义。但是,在这种情况下,我不认为样板太糟糕了。
mod
:
mod = alt *** alt
使用Control.Arrow.(***) - 在类型签名中将a b c
读为b -> c
;箭头只是一个通用的抽象(如仿函数或monad),其函数是一个实例。您可能希望定义both = join (***)
(这本身就是both f = f *** f
的简写);我知道至少有一个人使用这个别名,我认为它应该在Control.Arrow中。
所以,一般来说,答案是:组合器,组合器,组合器!这与point-free风格直接相关。它可能过头了,但是当组合器适合你的情况时,这样的代码不仅更简洁,更简单,更容易阅读:你只需要学习一次抽象,然后在阅读代码时可以随处应用。
我建议使用Hoogle找到这些组合器;当你认为你看到定义的一般模式时,尝试抽象出你认为常见部分是什么,获取结果的类型,并在Hoogle上搜索它。您可能会找到一个能够满足您需求的组合器。
因此,例如,对于您的mod
案例,您可以抽象出alt
,产生\f (a,b) -> (f a, f b)
,然后搜索其类型(a -> b) -> (a, a) -> (b, b) - 这是完全匹配,但它在fgl图库中,您不想依赖它。不过,你可以看到按类型搜索的能力确实非常有价值!
还有一个命令行版本的Hoogle与GHCi集成;有关详细信息,请参阅其HaskellWiki page。
答案 1 :(得分:4)
对于某些样板文件,Data.Function.on
可能会有所帮助,尽管在这些示例中,它并没有太大的成就
instance Ord Foo where
(<=) = (<=) `on` modify -- maybe
mod = uncurry ((,) `on` alt) -- Not really