2017-01-21 8 views
1

タイプa -> b -> Boolの関数リストを持っており、それらを2つの入力に適用し、結果をAllまたはAnyと組み合わせようとしています。私はこの1つの変数の機能と連携している:Haskellの2つの引数にブール関数のリストを適用します。

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

が、私は2つの変数の関数と同じことを行う方法を見つけ出すことはできません。

これは動作します:

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

だからあなたの最初の関数は、私が代わりにmconcat . map (All .)andを使用してい

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

のように記述することができます。

第2の機能の場合は、uncurryが適切なツールです。 uncurryをバイナリ関数のリストにマップして、タプルの単項関数のリストを取得しなければならないので、sequenceAを使用して1つの引数を取り出すことができます。 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 
関連する問題