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

时间:2012-07-29 12:46:23

标签: haskell pointfree

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

foobar x = [id x, reverse x]

到目前为止我用无点符号表达了我的想法:

foobar' = `map` [id, reverse] ($ x)

我似乎无法在那里结束x

4 个答案:

答案 0 :(得分:26)

其他人已经发布了如何使用Reader monad执行此操作,但这不是唯一的方法。事实证明你的第二个功能非常接近。我想你想发布

foobar' x = (`map` [id, reverse]) ($ x)

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

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

接下来,通过将新变量放入范围并将该函数应用于x

,从lambda主体中删除x
-- lambda abstraction I think...
foobar'2 x = (`map` [id, reverse]) $ (\z y -> ($) y z) x

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

-- 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)

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

替换lambda
-- by definition of `flip`
foobar'5 = (`map` [id,reverse]) . flip ($)

你有一个无点的形式。

答案 1 :(得分:10)

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

instance Applicative (e ->)

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

liftA2 (+) sin cos 3

此处sincos是函数,它们都接收值3.然后使用(+)合并各个结果。您可以进一步将其与Category的{​​{1}}实例结合使用,但(->)(.)的cource专用版本已在id中定义。

背景:Prelude的{​​{1}}实例实际上代表了SKI演算,其中Applicative S 组合,(e ->)是< em> K 组合子。 S 正好用于将参数分配给两个函数:

(<*>)

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

答案 2 :(得分:10)

使用sequence

> let foobar' = sequence [id, reverse]
> foobar' "abcde"
["abcde","edcba"]

答案 3 :(得分: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)

等。当然,uncurry f (x,y) == f x y也会被大量使用。

&&&***Control.Arrow以及firstsecond中定义。然后是prod (f,id) == first fprod(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)

对于最后一个,您还需要导入Control.MonadControl.Monad.Instances。另请参阅this question


延迟编辑:,使用 ertes 回答提示Control.Applicative

       = (:) <*> ((:[]) . reverse)