用于将两个函数应用于单个输入的Pointfree(或库)函数

bsh*_*urd 8 haskell pointfree

我一直在重用lambda表达式,例如

\x -> (f x, g x)
Run Code Online (Sandbox Code Playgroud)

我将相同的输入应用于两个函数并将结果封装在一对中.我可以编写一个捕获它的函数

combine :: (a -> b) -> (a -> c) -> a -> (b,c)
combine f g x = (f x, g x)
Run Code Online (Sandbox Code Playgroud)

现在上面的lambda表达式就是这样combine f g.我有两个问题.

  1. 我很想知道是否有一个标准的库函数可以做到这一点我找不到.
  2. 出于好奇,我想以无点的方式重写这个功能,但我遇到了很多麻烦.

sha*_*haf 12

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

  2. 你通常可以算这样的事情自动pointfree,其lambdabot#haskell具有作为一个插件.

例如:

<shachaf> @pl combine f g x = (f x, g x)
<lambdabot> combine = liftM2 (,)
Run Code Online (Sandbox Code Playgroud)

liftM2(r ->)实例Monad有型(a -> b -> c) -> (r -> a) -> (r -> b) -> r -> c.当然,根据您允许的原语,还有许多其他方法可以无点编写.


C. *_*ann 12

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

由于类型类很容易错过,但请注意Control.Arrow.平原Arrow不能被涂上或涂抹,因此Arrow组合器必须是无点的.如果你专注于它们(->),你会发现你想要的是这个:

(&&&) :: (Arrow a) => a b c -> a b c' -> a b (c, c')
Run Code Online (Sandbox Code Playgroud)

还有其他类似的函数,比如等效的操作Either,专门(->)看起来像这样:

(|||) :: (a -> c) -> (b -> c) -> Either a b -> c
Run Code Online (Sandbox Code Playgroud)

哪个是一样的either.

出于好奇,我想以无点的方式重写这个功能,但我遇到了很多麻烦.

既然你重复输入,你需要做的是pointfree的一些方法-最常见的方式是通过ApplicativeMonad实例(->),例如.这本质上是一个隐式的内联monad,被拆分的参数是"环境"值.使用这种方法,成为,或成为,成为,并成为小号组合子.\f g -> (,) <$> f <*> gReaderjoin f xf x xpurereturnconstfmap(.)(<*>) \f g x -> f x (g x)

  • Control.Arrow函数很难错过的部分原因是Hoogle不会将类型变量与` - >`统一起来,即使种类匹配,所以[Hoogling for`(a - > b) - >(a - > 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+- %3E + f + a +(b%2Cc)和(带警告)[Hoogling for((a~> b) - >(a~> c) - >(a〜>(b,c))一样工作`](http://www.haskell.org/hoogle/?hoogle=%28a+~%3E+b%29+-%3E+%28a+~%3E+c%29+-%3E+a+~%3E+% 28B%2CC%29)). (2认同)

ert*_*tes 6

实际上有很多方法可以做到这一点.最常见的方法是使用以下(&&&)功能Control.Arrow:

f &&& g
Run Code Online (Sandbox Code Playgroud)

但是,通常你有更多的功能或需要将结果传递给另一个函数,在这种情况下使用applicative样式会更方便.然后

uncurry (+) . (f &&& g)
Run Code Online (Sandbox Code Playgroud)

liftA2 (+) f g
Run Code Online (Sandbox Code Playgroud)

如上所述,这可以与多个功能一起使用:

liftA3 zip3 f g h
Run Code Online (Sandbox Code Playgroud)