95

このHaskellコードでドット演算子が何をしているのかを理解しようとしています:

sumEuler = sum . (map euler) . mkList

ソースコード全体は以下。

私の理解

ドット演算子は、2 つの関数sumと の結果map eulerおよび の結果をmkList入力として取っています。

でも、sum関数じゃないですか、関数の引数ですよね?それで、ここで何が起こっているのですか?

また、何をしているの(map euler)ですか?

コード

mkList :: Int -> [Int]
mkList n = [1..n-1]

euler :: Int -> Int
euler n = length (filter (relprime n) (mkList n))

sumEuler :: Int -> Int
sumEuler = sum . (map euler) . mkList
4

6 に答える 6

149

簡単に言えば、.数学と同じように、関数合成です。

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

あなたの場合、次のsumEulerように定義することもできる新しい関数を作成しています。

sumEuler x = sum (map euler (mkList x))

あなたの例のスタイルは「ポイントフリー」スタイルと呼ばれます-関数への引数は省略されています。これにより、多くの場合、コードがより明確になります。(初めて見たときは理解するのが難しいかもしれませんが、しばらくすると慣れます。Haskell の一般的なイディオムです。)

それでも混乱する場合は .、UNIX パイプのようなものに関連付けると役立つ場合があります。fの出力がgの入力になり、その出力がの入力になる場合hは、コマンドラインに のように記述しますf < x | g | h。Haskell では.、UNIX のように動作します|が、「後方」です -- h . g . f $ x. この表記法は、たとえばリストを処理するときに非常に役立つことがわかりました。のような扱いにくい構造の代わりに、map (\x -> x * 2 + 10) [1..10]単に と書くことができます(+10) . (*2) <$> [1..10]。(そして、その関数を単一の値にのみ適用したい場合;それは(+10) . (*2) $ 10.一貫性があります!)

Haskell wiki には、より詳細な優れた記事があります: http://www.haskell.org/haskellwiki/Pointfree

于 2009-03-10T17:07:51.480 に答える
32

。operator は関数を構成します。例えば、

a . b

abが関数である場合、引数に対して b を実行し、次にそれらの結果に対して a を実行する新しい関数です。あなたのコード

sumEuler = sum . (map euler) . mkList

は次とまったく同じです:

sumEuler myArgument = sum (map euler (mkList myArgument))

しかし、うまくいけば読みやすくなります。map eulerが括弧で囲まれている理由は、 summap eulermkListの3 つの関数が構成されていることが明確になるためです。 map eulerは単一の関数です。

于 2009-03-10T17:10:05.343 に答える
27

sumは Haskell Prelude の関数であり、 の引数ではありませんsumEuler。それはタイプを持っています

Num a => [a] -> a

関数合成演算子. には型があります

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

だから私たちは持っています

           euler           ::  Int -> Int
       map                 :: (a   -> b  ) -> [a  ] -> [b  ]
      (map euler)          ::                 [Int] -> [Int]
                    mkList ::          Int -> [Int]
      (map euler) . mkList ::          Int ->          [Int]
sum                        :: Num a =>                 [a  ] -> a
sum . (map euler) . mkList ::          Int ->                   Int

Intは確かに型クラスのインスタンスであることに注意してくださいNum

于 2009-03-10T18:15:24.157 に答える
12

。演算子は関数合成に使用されます。関数 f(x) と g(x) f が必要な場合は、数学と同じです。g は f(g(x)) になります。

map は、関数をリストに適用する組み込み関数です。関数を括弧で囲むことにより、関数は引数として扱われます。これの用語はカリー化です。あなたはそれを調べる必要があります。

つまり、2 つの引数を持つ関数を受け取り、引数 euler を適用します。(マップ オイラー) ですよね?結果は、引数を 1 つだけ取る新しい関数です。

合計。(マップオイラー) . mkList は基本的に、これらすべてをまとめるための凝った方法です。私のHaskellは少し錆びていると言わざるを得ませんが、最後の関数を自分で組み立てることができますか?

于 2009-03-10T17:08:08.377 に答える
4

ドット演算子は、左側の関数 ( sum) を右側の関数の出力に適用します。あなたの場合、いくつかの関数を一緒に連鎖させています - の結果を to に渡し、その結果をmkListto(map euler)に渡しsumます。 このサイトには、いくつかの概念の優れた紹介があります。

于 2009-03-10T17:09:09.217 に答える