Оператор точки в Haskell: нужно больше объяснений
Я пытаюсь понять, что делает оператор dot в этом коде Haskell:
sumEuler = sum . (map euler) . mkList
весь исходный код ниже.
мое понимание
оператор точки принимает две функции 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
6 ответов:
просто
.
это композиция функций, как и в математике:f (g x) = (f . g) x
в вашем случае, вы создаете новую функцию,
sumEuler
Это также может быть определено следующим образом:sumEuler x = sum (map euler (mkList x))
стиль в вашем примере называется стилем "без точек" - аргументы функции опущены. Это делает более четким код во многих случаях. (Это может быть трудно понять в первый раз вы видите его, но вы привыкнете к нему через некоторое время. Это общий Хаскелл идиома.)
если вы все еще смущены, это может помочь связать
.
к чему-то вроде трубы UNIX. Если 's становитсяg
's вход, выход которого становитсяh
Вход, вы бы написать, что в командной строке, какf < x | g | h
. В Хаскелле,.
работает как 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
sum
является функцией в прелюдии Хаскелла, а не аргументом для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
отметим, что
Int
примерNum
.
The . оператор составляет функции. Например,
a . b
здесь a и b функции-новый функции который запускает b по своим аргументам, а затем a по этим результатам. Ваш код
sumEuler = sum . (map euler) . mkList
- Это точно так же, как:
sumEuler myArgument = sum (map euler (mkList myArgument))
но, надеюсь, легче читать. Причина есть parens вокруг карта Эйлера это потому, что это делает его более ясным, что есть 3 функции составляются: sum,карта Эйлера и mkList -карта Эйлера это одна функция.
The . оператор используется для композиции функций. Так же, как математика, если у вас есть функции f(x) и g(x) f . g становится f(g (x)).
карта-это встроенная функция, которая применяет функцию к списку. Помещая функцию в круглые скобки, функция рассматривается как аргумент. Термин для этого карринг. Вы должны посмотреть это.
Что делает, так это то, что он принимает функцию с двумя аргументами, она применяет аргумент Эйлера. (карта Эйлера) верно? и в результате получается новая функция, которая принимает только один аргумент.
сумма . (карта Эйлера) . mkList-это в основном причудливый способ собрать все это вместе. Я должен сказать, что мой Haskell немного ржавый, но, может быть, вы можете собрать эту последнюю функцию самостоятельно?
оператор точки применяет функцию слева (
sum
) к выходу функции справа. В вашем случае вы связываете несколько функций вместе - вы передаете результатmkList
to(map euler)
, а затем передать результат этого вsum
. этот сайт имеет хорошее введение в несколько концепций.
оператор точки в Haskell
я пытаюсь понять, что делает оператор dot в этом коде 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)
(.)
- это compose operator.написать
в математике мы могли бы написать состав функций f(x) и g(x), то есть f(g (x)), как
(f ∘ g) (x)
где можно прочитать "f состоит из g".
таким образом, в Haskell, f ∘ g или f, состоящие из g, могут быть написаны:
f . g
композиция ассоциативна, что означает, что f(g(h(x))), записанный с помощью оператора композиции, может оставить скобки без какой-либо двусмысленности.
то есть, с (ф ∘ г) ∘ ч приравнивается к F ∘ (г ∘ ч), можно просто писать F ∘ г ∘ з.
возвращается
возвращаясь к нашему предыдущему упрощению, это:
sumEuler = sum . map_euler . mkList
просто означает, что
sumEuler
является неприменимой композицией этих функций:sumEuler = \x -> sum (map_euler (mkList x))