2016-07-06 101 views
7

我想了解以下内容在完成点免费电话:Haskell函数组合 - (a - > b) - >(a - > c) - >(b - > c - > d) - >(a - > d)

withinBounds :: [Int] -> Bool 
withinBounds xs = (all (>= 0) xs) && (all (<= 8) xs) 

我明白,这是优于它这种方式可读性/理智的缘故写的,但我想更多地了解我如何可以撰写功能。我一直在挠我的脑袋,以至于我该如何做到这一点。 全体(扩大?)型签名

[Int] -> ([Int] -> Bool) -> ([Int] -> Bool) -> (Bool -> Bool -> Bool) -> Bool 

我试图让该组合物的类型签名是

(a -> b) -> (a -> c) -> (b -> c -> d) -> (a -> d) 

我写了下面作为一个私生子 - 拉姆达形式笔记。如果有一种方法在一定程度上简化与演算的问题,这将会是巨大的,如果可能太解释说:

\[email protected][] -> \[email protected]([] -> Bool) -> \[email protected]([] -> Bool) -> \[email protected](Bool -> Bool -> Bool) -> f3.(f1.L).(f2.L) 

在上面,.是应用程序,@被捕获(使F3是另一种(Bool - > Bool - > Bool)的名称)。 非常感谢。

编辑:我知道这不是最优化或可重用的代码,我知道将其转换为无点代码会使其在可读性等方面变得更糟。为了澄清,我在问如何将其转化为点 - 免费,因为我想了解更多关于haskell和作文

EDIT2:A really good SO answer on point-free

+3

你'withinBounds'不是组合的,最好是写一个单一元素的检查,然后调用'all'上。实际上,我可能只需将inBounds内的'all withinBounds'内联到一个单独的元素中。 –

+0

谢谢。是否有一个功能不可组合的迹象? (例如在身体的多个位置需要输入?) – MIJOTHY

+1

@MIJOTHY:通常,如果类型更一般,它可能更易于重用,例如, 'withinBounds :: Ord e =>(e,e) - > e - > Bool; withinBounds(a,b)x = a <= x && x <= b'。现在你的原始函数只是'all(withinBounds(0,8))'。此外,我可以用它作为过滤器的谓词:'filter(withinBounds(4,100))[1..103]'。 – Zeta

回答

2

否则周围的整个问题的最终来说,我认为我可能会写这种方式:

import Data.Ix 
withinBounds = all (inRange (0, 8)) 

当然,这是撑船了一下,因为一会又自然会问如何实现inRange一个无点的方法。如果你绝对不能使用inRange,那么我会实现它内联这样:

withinBounds = all (liftA2 (&&) (>=0) (<=8)) 

它使用阅读器应用性供应的一个参数两种功能。 liftA2是您要求的合成功能,虽然与翻转参数:

requested :: (a -> b) -> (a -> c) -> (b -> c -> d) -> (a -> d) 
liftA2 :: (b -> c -> d) -> (a -> b) -> (a -> c) -> (a -> d) 
+0

哦,我明白了!所以既然'liftA2 f a b = fmap f a <*> b'''f <$> x = fmap f x','liftA2 f a b = f <$> a <*> b'这很好地连接到了@ Safareli的答案。 – MIJOTHY

+0

因为对于(( - >)r)'fmap =(。)',它也可以被写入'withinBounds =(&&)。 (全部(> = 0))<*>(全部(<= 8))' – MIJOTHY

9

你可以使用一个事实,即功能是应用型。 写withinBounds这样:

withinBounds = pure (&&) <*> all (>= 0) <*> all (<= 8) 

或者这样说:

withinBounds = (&&) <$> all (>= 0) <*> all (<= 8) 

你可以读到Applicatives herehere

+0

@MIJOTHY你是对的 – Safareli

+0

为什么我的评论被删除/为什么它消失了? – MIJOTHY

+1

不知道:/昨天它有两个upvotes,一个从我 – Safareli

9

有一个这基本上是专门为自由点的组合物†类具有多个“频道”的Arrow。如果你决定让所有事情都没有问题,那么这就是IMO的出路。关于这个丑陋的一点是,你需要不断uncurry功能:

import Control.Arrow 

withinBounds = all (>=0) &&& all (<=8) >>> uncurry (&&) 

这如何与一个图是最好的理解:

 all (>=0) ──── 
     ╱    ╲ 
──── &&&   >>> uncurry (&&) ─── 
     ╲    ╱ 
     all (<=8) ──── 

Arrow作品在广义设置;不仅仅适用于Hask函数,而是适用于任何合适的类别。但仅仅将它用于功能足够有用。

+0

谢谢,图也真的有帮助。我会做一些关于箭头的阅读。 – MIJOTHY

-2

注意,X < = 8当且仅当8-X> = 0,所以,只使用前奏,我们可以写

withinBounds :: [Int] -> Bool 
withinBounds = all $ (all (>=0)) . (zipWith (+) [0,8]) . (zipWith (*) [1,-1]) . (replicate 2) 

基本上我刚映射x[x,x]然后[x,8-x]然后我需要这两个同时> = 0。

当然,正如评论中指出的那样,您也可以制作a,b参数,以便稍后重用它们。

希望这会有所帮助。

+0

贬低投票者的关心是否要解释投票的原因,以便我可以改进呢?事实上,这个技巧在其他类似的任务中也很有用,并且不需要像其他答案那样的高级知识。 – awllower

+2

这是非常难以理解的。 – chepner

+0

好吧,OP在问题主体中表示可读性不是这里关心的问题:他只是想知道如何以无点的方式编写这些内容。另外,我添加了一个解释来完成这个功能的过程。也许我会解释更多?无论如何,谢谢你的回复。 – awllower

相关问题