質問

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

sumEuler = sum . (map euler) . mkList

ソースコード全体は以下のとおりです。

私の理解

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

しかし、(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))

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

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

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

他のヒント

演算子は関数を構成します。たとえば、

a . b

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

sumEuler = sum . (map euler) . mkList

は次とまったく同じです

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

しかし、うまくいけば読みやすくなります。 map euler の周りに括弧があるのは、 sum map euler および mkList - map euler は単一の関数です。

sumはHaskell Preludeの関数であり、sumEulerの引数ではありません。タイプがあります

Num a => [a] -> a

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

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

つまり

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

IntNumのインスタンスであることに注意してください。

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

mapは、リストに関数を適用する組み込み関数です。関数を括弧で囲むことにより、関数は引数として扱われます。この用語は、カリーです。調べてください。

は、2つの引数を持つ関数を受け取り、引数オイラーを適用するということです。 (マップオイラー)そうですか?結果は新しい関数になり、引数は1つだけになります。

sum。 (マップオイラー)。 mkListは基本的に、それらすべてをまとめる素晴らしい方法です。私のHaskellは少しさびていますが、最後の機能を自分で組み立てることができますか?

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

  

Haskellのドット演算子

     

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

sumEuler = sum . (map euler) . mkList

簡単な回答

ドットなしの同等のコード、それはただ

sumEuler = \x -> sum ((map euler) (mkList x))

またはラムダなし

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

ドット(。)は関数の構成を示すため。

長い回答

最初に、eulerからmapへの部分適用を単純化しましょう:

map_euler = map euler
sumEuler = sum . map_euler . mkList

これでドットができました。これらのドットは何を示していますか?

ソース

(.)    :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)

したがって、(.)作曲演算子です。

作成

数学では、関数f(x)とg(x)の合成、つまりf(g(x))を次のように記述できます

  

(f <!>#8728; g)(x)

これは読むことができます<!> quot; fはg <!> quot;で構成されます。

つまり、Haskellでは、f <!>#8728; gまたはfをgで構成すると、次のように記述できます。

f . g

構成は結合的です。つまり、構成演算子で記述されたf(g(h(x)))は、あいまいさなしに括弧を省略できます。

つまり、(f <!>#8728; g)<!>#8728; hはf <!>#8728と同等です。 (g <!>#8728; h)、単にf <!>#8728;と書くことができます。 g <!>#8728; h。

戻る

以前の単純化に戻って、これ:

sumEuler = sum . map_euler . mkList

は、単にsumEulerがこれらの関数の適用されていない構成であることを意味します。

sumEuler = \x -> sum (map_euler (mkList x))
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top