Pergunta

Eu estou tentando entender o que o operador ponto está fazendo neste código Haskell:

sumEuler = sum . (map euler) . mkList

O código fonte inteira está abaixo.

O meu entendimento

O operador ponto está levando a duas funções sum eo resultado da map euler eo resultado da mkList como entrada.

Mas, sum não é uma função é o argumento da função, certo? Então, o que está acontecendo aqui?

Além disso, o que é (map euler) fazendo?

Código

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
Foi útil?

Solução

Simplificando, . é composição de função, assim como em matemática:

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

No seu caso, você está criando uma nova função, sumEuler que também poderia ser definido assim:

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

O estilo no seu exemplo é chamado de "livre-point" estilo - os argumentos para a função são omitidos. Isto faz para código mais claro em muitos casos. (Pode ser difícil para Grokar a primeira vez que você vê-lo, mas você vai se acostumar a ele depois de um tempo. É uma expressão comum Haskell.)

Se você ainda está confuso, ele pode ajudar a relacionar . para algo como um tubo de UNIX. Se a saída do f torna-se a entrada do g, cuja produção se torna a entrada do h, você escreveria que na linha de comando como f < x | g | h. Em Haskell, . funciona como o | UNIX, mas "para trás" - h . g . f $ x. Acho que esta notação a ser bastante útil quando, por exemplo, o processamento de uma lista. Em vez de algumas obras de difícil controle como map (\x -> x * 2 + 10) [1..10], você poderia simplesmente escrever (+10) . (*2) <$> [1..10]. (E, se você quiser aplicar apenas essa função para um único valor;.!-Lo de (+10) . (*2) $ 10 Consistente)

O wiki Haskell tem um bom artigo com mais algum detalhe: http://www.haskell.org/ haskellwiki / pointfree

Outras dicas

A. operador compõe funções. Por exemplo,

a . b

Onde a e b são funções é um novo Função que corre b em seus argumentos, então uma base nesses resultados. Seu código

sumEuler = sum . (map euler) . mkList

é exatamente o mesmo que:

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

mas espero mais fácil de ler. A razão existem parênteses em torno de Mapa Euler é porque torna mais claro que há 3 funções sendo composta: sum , Mapa Euler e mkList -. mapa Euler é uma única função

sum é uma função no Prelude Haskell, não um argumento para sumEuler. Ele tem o tipo

Num a => [a] -> a

O . operador composição de função tem tipo

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

Portanto, temos

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

Note que Int é uma instância de Num.

A. operador é utilizado para a composição de função. Assim como matemática, se você tem que funções f (x) eg (x) f. g torna-se f (G (x)).

mapa é um built-in função que aplica uma função a uma lista. Colocando a função em parênteses a função é tratado como um argumento. Um termo para isso é currying . Você deve olhar isso.

O que é que é que ele tem uma função com digamos dois argumentos, aplica-se a Euler argumento. (Mapa Euler) certo? eo resultado é uma nova função, que tem apenas um argumento.

sum. (Mapa Euler). mkList é basicamente uma maneira extravagante de colocar tudo isso junto. Devo dizer, meu Haskell é um pouco enferrujado, mas talvez você possa colocar essa última função junto a si mesmo?

O operador ponto aplica a função à esquerda (sum) para a saída da função no lado direito. No seu caso, você está encadeamento várias funções em conjunto - você está passando o resultado de mkList para (map euler), e em seguida, passando o resultado de que a sum. Este site tem uma boa introdução a vários dos conceitos.

Dot Operador em Haskell

Eu estou tentando entender o que o operador ponto está fazendo neste código Haskell:

sumEuler = sum . (map euler) . mkList

Resposta curta

código equivalente sem pontos, que é apenas

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

ou sem a lambda

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

porque o ponto (.) Indica composição de função.

resposta mais longa

Primeiro, vamos simplificar a aplicação parcial de euler para map:

map_euler = map euler
sumEuler = sum . map_euler . mkList

Agora só temos os pontos. O que é indicado por esses pontos?

De a fonte :

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

Assim (.) é o componha operador .

Compose

Em matemática, podemos escrever a composição de funções, f (x) eg (x), isto é, f (g (x)), como

(f ° g) (x)

que pode ser lido "f composta com g".

Assim, em Haskell, f ° g ou f composta com g, pode ser escrita:

f . g

Composição é associativa, o que significa que f (g (h (x))), escrito com o operador de composição, pode deixar de fora os parênteses sem qualquer ambiguidade.

Isto é, uma vez que (f ° g) ° h é equivalente a f ° (g h °), podemos simplesmente escrever f ° g ° h.

Circular volta

Circular de volta ao nosso simplificação anteriormente, esta:

sumEuler = sum . map_euler . mkList

apenas significa que sumEuler é uma composição unapplied dessas funções:

sumEuler = \x -> sum (map_euler (mkList x))

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top