2013-01-16 12 views
8

我保持重用lambda表达式如Pointfree(或文库)函数用于将两个功能到单输入

\x -> (f x, g x) 

其中I施加输入到两个相同的功能和封装该结果中的一对。我可以写一个函数来捕获这个

combine :: (a -> b) -> (a -> c) -> a -> (b,c) 
combine f g x = (f x, g x) 

现在上面的lambda表达式只是combine f g。我有两个问题。

  1. 我很想知道是否有一个标准的库函数来做到这一点,我找不到。
  2. 出于好奇,我想用无点的风格重写这个函数,但是我遇到了很多麻烦。

回答

12
  1. Control.Arrow具有此功能(&&&)。它有一个“更一般”的类型,不幸意味着Hoogle没有找到它(可能这应该被认为是Hoogle中的一个错误?)。

  2. 通常你可以用pointfree自动计算出这种东西,其中lambdabot#haskell作为一个插件。

例如:

<shachaf> @pl combine f g x = (f x, g x) 
<lambdabot> combine = liftM2 (,) 

liftM2凡与Monad(r ->)实例已键入(a -> b -> c) -> (r -> a) -> (r -> b) -> r -> c。当然,根据您允许的原语,还有很多其他写这个点的方法。

+0

感谢您的回答言简意赅,并感谢指着我pointfree。 – bshourd

12

我很想知道是否有一个标准库函数可以做到这一点,我找不到。

很容易因为类型错过,但是look at Control.Arrow。平原Arrow不能咖喱或应用,所以Arrow组合器是必要的。如果你擅长他们(->),你会发现你想要的是这样的:

(&&&) :: (Arrow a) => a b c -> a b c' -> a b (c, c') 

还有其他类似的功能,如Either等效操作,专门以(->)看起来是这样的:

(|||) :: (a -> c) -> (b -> c) -> Either a b -> c 

either相同。

出于好奇,我想以无点式重写这个函数,但是我遇到了很多麻烦。

既然你重复输入,你需要做的是pointfree的一些方法 - 最常见的方式是通过ApplicativeMonad实例(->),例如\f g ->(,) < $ >˚F< *“G 。这本质上是一个隐含的内联Reader monad,并且分解的参数是“环境”值。使用这种方法,join f x变得f x xpurereturn成为constfmap变得(.)(<*>)成为S combinator\f g x -> f x (g x)

+2

Control.Arrow函数很难忽略的部分原因是Hoogle不会使用' - >'统一类型变量,即使种类匹配,所以[为(a - > b) - > - > c) - > a - >(b,c)'](http://www.haskell.org/hoogle/?q=(a + - %3E + b)+ - %3E +(a + - %3E + c)+ - %3E + a + - %3E +(b%2Cc))找不到'(&&&)'。 ([搜寻fab - > fac - > fa(b,c)'](http://www.haskell.org/hoogle/?q=f+a+b+-%3E+f+a+c+- (a〜> c) - >(a〜>(b,c))(%)3E + f + a +(b%2Cc) '](http://www.haskell.org/hoogle/?hoogle=%28a+~%3E+b%29+-%3E+%28a+~%3E+c%29+-%3E+a+~%3E+% 28b%2Cc%29))。 –

+1

谢谢你们两位,这正是我想知道的。感谢Antal指出Hoogle的'a〜> b'语法,我不知道。 – bshourd

6

实际上有很多种方法。最常见的方式是使用(&&&)功能从Control.Arrow

f &&& g 

然而,往往你有更多的功能或需要将结果传递给另一个函数,在这种情况下,它是更方便地使用应用性的风格。然后

uncurry (+) . (f &&& g) 

成为

liftA2 (+) f g 

如上所述这可以用一个以上的功能使用:

liftA3 zip3 f g h 
+0

谢谢,特别是对于“使用多个功能”的解释 – bshourd

+1

这些当然可以用'<$>'和'<*>':'zip3 <$> f <*> g <*> h'重写,有时候这比使用'liftA * '。 –

相关问题