2012-07-29 25 views
25

我有一天很无聊,想锻炼我的大脑,所以我决定去做99 Haskell Problems,但我限制自己以无点式的方式做。当我以无点式的方式做事情时,似乎出现了很多问题:如何将多个函数应用于相同的值,同时将每个结果保留为独立的实体?使用尖锐的表示法:在Haskell中将多个函数应用于相同的无值点式样

foobar x = [id x, reverse x] 

什么,我拿出迄今无点符号:

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

我似乎无法得到那个x过那里的结束。

回答

25

其他人已经发布了如何可以使用Reader单子做到这一点,但是这不是唯一的方法。事实证明,你的第二个功能非常接近。我觉得你的意思后

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

请从拉姆达身体 x
-- lambda abstraction I think... 
foobar'2 x = (`map` [id, reverse]) $ (\z y -> ($) y z) x 

改写这个应用程序作为一个功能组成,然后你就可以ETA减少:

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

并且您有一个无点形式。

8

你会感兴趣的读者单子的Applicative实例:

instance Applicative (e ->) 

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

liftA2 (+) sin cos 3 

这里sincos的功能,既接收值3.然后使用(+)组合各个结果。您可以进一步将此与(->)Category实例组合,但(.)id的源专用版本已在Prelude中定义。

背景:Applicative实例(e ->)真正代表了SKI演算,其中(<*>)小号组合子和pureķ组合子。 小号被精确地用于一个参数分配到两个功能:

S f g x = f x (g x) 

它需要一个功能应用(FG)和使得无论依赖于值X(FX)(GX) )。

9

使用sequence

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

只有当你确定与约束。这不适用于所有用途。 – 2012-07-29 14:43:20

+0

@ ThomasM.DuBuisson:什么约束? – 2012-08-09 14:30:44

+0

@BenMillwood我指的是typeclass约束。 JohnL的答案是'a - > [a]'类型。这个答案虽然很好干净,但是类型为Monad(( - > a)=> a - > [a]' – 2012-08-09 15:57:47

5

有几个基本的惯用combinators反复弹出,并重新实现了各种高级概念和库,但实质上非常简单。名称可能会有所不同,而在其他方面有些是可实现的:

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


后期编辑:此外,使用Control.Applicativeertes回答暗示,

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

也可以,'(:) <*>(纯粹的反向)'((( - >)r),[ (' - ] r)'Monad'),'([id,reverse]')。 – 2016-04-23 20:08:09

相关问题