2017-01-21 128 views
1

我有一個a -> b -> Bool類型的函數列表,並且試圖將它們應用於兩個輸入並將結果與​​All或結合起來。我有這個工作與一個變量的功能:將布爾函數列表應用到Haskell中的兩個參數中

mconcat (map (All .) [(<7),(>7),(==7)]) $ 6 

但我不知道如何做兩個變量函數相同。

這工作:

mconcat (map (All .) (map (uncurry) [(<),(>),(==)])) $ (,) 6 7 

,但在我看來像一個醜陋的解決方法。

有沒有更好的方法來做到這一點?

回答

3

這是編寫自己的代碼 - 你只需要加入類型。但有幾個標準工具(即ApplicativeTraversable),您可以使用它們縮短代碼。

Data.Traversable模塊壽命sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)。當專門到Traversable[]的實例和功能應用性(->) r我們得到:

sequenceA :: [r -> a] -> r -> [a] 

所以sequenceA洋基->[],將各功能列表中的一個固定的說法。

sequenceA [(< 7), (> 7), (== 7)] :: (Num n, Ord n) => n -> [Bool] 
-- equivalent to: 
\n -> map ($ n) [(< 7), (> 7), (== 7)] 

所以你的第一個功能,可我使用and代替mconcat . map (All .)寫成

f :: (Num n, Ord n) => n -> Bool 
f = and . sequenceA [(< 7), (> 7), (== 7)] 

對於第二個功能,uncurry是正確的工具。我們必須將uncurry映射到二進制函數列表上以獲取元組的一元函數列表,以便我們可以使用sequenceA提升單個參數。因爲traverse f = sequenceA . map f我們可以把它寫成:

g :: Ord n => n -> n -> Bool 
g = curry $ and . traverse uncurry [(<), (>), (==)] 

(NB,爲Ord><任何正確實施的實例應該是相互排斥所以這兩個函數總是返回False。)

1

密切替代原來的代碼:

mconcat (map (\f a b -> All (f a b)) [(<),(<=)]) 3 4 

在一個毫無意義的風格,可以進一步改寫\f a b -> All (f a b)

mconcat (map ((.) (All .)) [(<),(<=)]) 3 4 
相關問題