2011-12-16 61 views
6

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

回答

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中。

所以,一般来说,答案是:combinators,combinators,combinators!这直接与point-free风格。它可以被过度使用,但是当组合器存在于你的情况下时,这样的代码不仅可以更清晰,更短,而且可以更容易阅读:你只需要学习一次抽象,然后在读取代码时将它应用到任何地方。

我建议使用Hoogle找到这些组合器;当你认为自己看到了定义的一般模式时,尝试抽象出你认为常见部分是什么,采取何种结果并在Hoogle上搜索。你可能会发现一个组合器,只是你想要的。

所以,举例来说,你mod情况下,可以抽象出alt,产生\f (a,b) -> (f a, f b),然后搜索它的类型,(a -> b) -> (a, a) -> (b, b) - 有一个精确匹配,但它是在FGL图形库,你不想依靠。不过,您可以看到按类型进行搜索的能力如何确实非常有价值!

还有一个带GHCi集成的Hoogle命令行版本;请参阅其HaskellWiki page了解更多信息。

(还有Hayoo,其搜索的Hackage全部,但稍显不足巧妙搭配类型;你用哪一个长达个人喜好)

4

对于一些样板,Data.Function.on可以是有益的,但在这些例子中,它并没有获得太多

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

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