2016-07-06 97 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

相關問題