1. ホーム
  2. haskell

[解決済み] Haskellのドット演算子:もっと説明が欲しい

2023-02-01 20:57:53

質問

この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

どのように解決するのですか?

簡単に言うと . は数学と同じように関数の合成です。

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

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

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

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

それでもまだ混乱しているのであれば、関連する . をUNIXのパイプのようなものに関連付けることができるかもしれません。 もし f の出力が g の入力となり、その出力は h の入力になるように、コマンドラインで次のように書きます。 f < x | g | h . Haskellでは . はUNIXの | と同じように働きますが、quot;backwards" -- です。 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