拆除普通的haskell管道样板

时间:2011-12-16 02:56:25

标签: haskell

我有一些很常见的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可以指向我正确的方向吗?

2 个答案:

答案 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

(还有Hayoo,它会搜索整个Hackage,但对于类型稍微不那么聪明;您使用的是个人偏好。)

答案 1 :(得分:4)

对于某些样板文件,Data.Function.on可能会有所帮助,尽管在这些示例中,它并没有太大的成就

instance Ord Foo where
    (<=) = (<=) `on` modify   -- maybe

mod = uncurry ((,) `on` alt)  -- Not really