在Haskell中将多个函数应用于相同的值无点样式

Dwi*_*son 27 haskell pointfree

有一天我很无聊,想锻炼我的大脑,所以我决定做99个Haskell问题但是限制自己以无点的方式做这些.当我以无点样式执行操作时,似乎出现了很多问题:如何将多个函数应用于相同的值,同时将每个结果保持为独立实体?使用尖头符号:

foobar x = [id x, reverse x]
Run Code Online (Sandbox Code Playgroud)

到目前为止我用无点符号得出了什么:

foobar' = `map` [id, reverse] ($ x)
Run Code Online (Sandbox Code Playgroud)

我似乎无法x在那里结束.

Joh*_*n L 26

其他人已经发布了如何使用Readermonad 来做到这一点,但这不是唯一的方法.事实证明你的第二个功能非常接近.我想你打算发帖

foobar' x = (`map` [id, reverse]) ($ x)
Run Code Online (Sandbox Code Playgroud)

由于x已经接近最右边的位置,你几乎就在那里.首先,将该部分($ x)转换为函数,因为它更容易使用:

-- by the definition of a right operator section
foobar'2 x = (`map` [id, reverse]) (\y -> ($) y x)
Run Code Online (Sandbox Code Playgroud)

接下来,x通过将新变量放入范围并将函数应用到lambda体中x

-- lambda abstraction I think...
foobar'2 x = (`map` [id, reverse]) $ (\z y -> ($) y z) x
Run Code Online (Sandbox Code Playgroud)

将此应用程序重写为函数组合,然后您可以减少:

-- by definition of '.'
foobar'3 x = (`map` [id, reverse]) . (\z y -> ($) y z) $ x

-- eta reduction
foobar'4 = (`map` [id, reverse]) . (\z y -> ($) y z)
Run Code Online (Sandbox Code Playgroud)

最后,请注意我们可以用函数替换lambda

-- by definition of `flip`
foobar'5 = (`map` [id,reverse]) . flip ($)
Run Code Online (Sandbox Code Playgroud)

你有一个无点的形式.


小智 11

您将对Applicative读者monad 的实例感兴趣:

instance Applicative (e ->)
Run Code Online (Sandbox Code Playgroud)

使用它您可以轻松分发参数:

liftA2 (+) sin cos 3
Run Code Online (Sandbox Code Playgroud)

这里sincos是函数,它们都接收值3.然后使用组合各个结果(+).您可以进一步将其与cource专用版本的Category实例相结合(->),(.)并且id已经在Prelude.

背景:真实的Applicative实例(e ->)代表SKI演算,其中(<*>)S组合子,pureK组合子. S正好用于将参数分配给两个函数:

S f g x = f x (g x)
Run Code Online (Sandbox Code Playgroud)

它需要一个函数应用程序(fg)并使两者都依赖于值x((fx)(gx)).


Mat*_*nov 10

使用顺序:

> let foobar' = sequence [id, reverse]
> foobar' "abcde"
["abcde","edcba"]
Run Code Online (Sandbox Code Playgroud)

  • @ThomasM.DuBuisson:那个上下文表示一个真正应该在Prelude中的缺失实例 - 如果你导入`Control.Monad.Instances`那么这个约束永远消失了.它适用于所有用途. (2认同)

Wil*_*ess 5

有一些基本的惯用组合器反复弹出,并重新实现了各种更高的概念和库,但基本上非常简单.名称可能有所不同,有些可以实现其他名称:

fork (f,g) x = (f x, g x)              -- == (f &&& g)
prod (f,g) x = (f $ fst x, g $ snd x)  -- == (f *** g)
pmap f (x,y) = (f x, f y)              -- == (f *** f)
dup     x    = (x,x)
Run Code Online (Sandbox Code Playgroud)

当然uncurry f (x,y) == f x y,这些也被大量使用了.

&&&***被定义在Control.Arrow,以及firstsecond.然后prod (f,id) == first f,prod(id,g) == second g等等,等等

所以你foobar变成了

foobar = (\(a,b)->[a,b]) . fork (id,reverse)
       = (\(a,b)->[a,b]) . (id &&& reverse)
       = (\(a,b)->[a,b]) . (id *** reverse) . dup 
       = join $ curry ( (\(a,b)->[a,b]) . second reverse)
Run Code Online (Sandbox Code Playgroud)

对于最后一个,您还需要导入Control.MonadControl.Monad.Instances.另见这个问题.


迟编辑:也可以使用ertes的Control.Applicative回答,

       = (:) <*> ((:[]) . reverse)
Run Code Online (Sandbox Code Playgroud)