9

かなり簡単なことをしたいです。Data.Map insertWithで演算子(++)を使用していますが、正常に機能しますが、作成された値の重複を排除したいので、nubで構成します。

(nub(++))、(nub $(++))、(nub。(++))を試しましたが、(++)のタイプが予想されるnubのタイプと一致しないため、まったく役に立ちませんでした。 ([a])。

もちろん補助関数やラムダを定義することもできますが、もっと明確な構成があるのではないかと思います。

ヒントをお願いします!

4

5 に答える 5

11

あなたはこれを次のように書くことができます

((nub .) .) (++)

例:

Prelude Data.List> ((nub .) .) (++) [1,2,3] [3,4,5]
[1,2,3,4,5]

一般的に、あなたは

(f . ) g x = f (g x) 
((f . ) . ) g x y = f (g x y) 
(((f . ) . ) . ) g x y z = f (g x y z) 
((((f . ) . ) . ) . ) g x y z v = f (g x y z v)
...

このアイデンティティの派生は次の((nub .) .)とおりです。

(f . g) x = f (g x)

(nub .) :: Eq a1 => (a -> [a1]) -> a -> [a1] 
(nub .) = \g x -> (nub (g x))

((nub .) .) :: Eq a2 => (a -> a1 -> [a2]) -> a -> a1 -> [a2]
((nub .) .) = ((\g x -> (nub (g x))) .) = (\g' x' -> (\g x -> (nub (g x))) (g' x'))
            = \g' x' x -> (nub ((g' x') x))

この(および関連する)イディオムについての素晴らしい記事がありますが、それはロシア語です:-(

于 2011-07-06T16:02:08.737 に答える
6

必要なのは、次のような2進関数と単項関数の合成のようです。

compose :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)
compose unary binary a b = unary (binary a b)

そして、ポイントフリーバージョンを要求します(変数については言及しません)abそれらを一つずつ排除していきましょう。b次の事実を使用して、から始めますf (g x) = f . g

compose unary binary a = unary . binary a

a次です。最初に式を脱糖しましょう:

compose unary binary a = ((.) unary) (binary a)

そして、同じ構成ルールを再度適用します。

compose unary binary = ((.) unary) . binary

これはさらに次のように書くことができます:

compose unary = (.) ((.) unary)

またはとしても

compose = (.) . (.)

ここで、各(.)'は'バイナリ関数から引数を取り除きます。関数はバイナリであるため、そのうちの2つが必要です。このイディオムは、任意のファンクターに一般化された場合に非常に役立ちます:(関数がファンクターと見なされる場合と同等であることにfmap . fmap注意してください)。これにより、ファンクターを「取り除く」ことができます。たとえば、次のように書くことができます。fmap.

incrementResultsOfEveryFunctionInTwoDimentionalList :: [[String -> Integer]] -> [[String -> Integer]]
incrementResultsOfEveryFunctionInTwoDimentionalList = fmap . fmap . fmap $ (+1)

したがって、結果は次のようになります。

(fmap . fmap) nub (++)

編集:

私の脳が再現しようとしていた答えを見つけたと思います:タイプ(c→d)→(a→b→c)→(a→b→d)のHaskell関数合成演算子

于 2011-07-06T15:56:33.307 に答える
3

この問題は、セマンティックエディターコンビネーターによって特にシンプルで美しい方法で解決されます。与える:

最終的な構成は次のようになります。

(result.result) nub (++)
于 2011-07-06T17:09:35.390 に答える
1

やや変な見た目の(.).(.)コンビネータを使用できます。

Prelude> :set -XNoMonomorphismRestriction
Prelude> :m + Data.List
Prelude Data.List> let f = ((.).(.)) nub (++)
Prelude Data.List> :t f
f :: Eq a => [a] -> [a] -> [a]
Prelude Data.List> f "ab" "ac"
"abc"

whereただし、-clauseでラムダ関数または補助関数を使用する方が読みやすいでしょう。

于 2011-07-06T15:55:40.270 に答える
1

必要な合成演算子は、標準ライブラリに単一の関数として存在するとは思いません。それを書くための最短の方法はおそらく((.).(.))です。のFunctor定義を使用して、必要に応じて、または((->) t)として記述することもできます。fmap . fmapfmap fmap fmap

上記のすべてはかなり不可解ですが、イディオムは十分に一般的であるため、多くの人があなたがしていることを認識します。

ちなみに、Haskellで2つの引数の関数を「ダイアディック」と呼ぶのは避けたいと思うかもしれません。なぜなら、その用語を1つの引数の関数に拡張すると、人々を本当に混乱させるからです。

関連する議論については、この質問も参照してください。

このライブラリには、非常に直感的な名前のコンビネータがたくさんあります。

于 2011-07-06T15:57:01.467 に答える