Estou tentando entender o que o operador ponto está fazendo neste código Haskell:
sumEuler = sum . (map euler) . mkList
Todo o código-fonte está abaixo.
Meu entendimento
O operador ponto toma as duas funções sum
e o resultado de map euler
e o resultado de mkList
como a entrada.
Mas, sum
uma função não é o argumento da função, certo? Então, o que está acontecendo aqui?
Além disso, o que está (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
fonte
f (g x)
=(f . g) x
"?) Ou algo mais?==
se quisesse Haskell padrão válido.O . operador compõe funções. Por exemplo,
a . b
Onde a e b são funções é uma nova 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 que seja mais fácil de ler. A razão de haver parênteses ao redor do euler do mapa é porque torna mais claro que há 3 funções sendo compostas: soma , euler do mapa e mkList - euler do mapa é uma função única.
fonte
sum
é uma função do Prelúdio de Haskell, não um argumento parasumEuler
. Tem o tipoNum a => [a] -> a
O operador de composição de função
.
tem tipoEntão nós temos
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
Observe que
Int
é realmente uma instância daNum
typeclass.fonte
O . operador é usado para a composição da função. Assim como a matemática, se você tiver que funções f (x) e g (x) f. g torna-se f (g (x)).
map é uma função incorporada que aplica uma função a uma lista. Ao colocar a função entre parênteses, a função é tratada como um argumento. Um termo para isso é currying . Você deveria pesquisar isso.
O que acontece é que recebe uma função com, digamos, dois argumentos, e aplica o argumento euler. (mapa euler) certo? e o resultado é uma nova função, que leva apenas um argumento.
soma (mapa euler). mkList é basicamente uma maneira sofisticada de colocar tudo isso junto. Devo dizer que meu Haskell está um pouco enferrujado, mas talvez você mesmo possa montar essa última função?
fonte
Resposta curta
Código equivalente sem pontos, isso é apenas
sumEuler = \x -> sum ((map euler) (mkList x))
ou sem o lambda
sumEuler x = sum ((map euler) (mkList x))
porque o ponto (.) indica a composição da função.
Resposta mais longa
Primeiro, vamos simplificar a aplicação parcial de
euler
paramap
:map_euler = map euler sumEuler = sum . map_euler . mkList
Agora temos apenas os pontos. O que é indicado por esses pontos?
Da fonte :
Assim
(.)
é o operador de composição .Compor
Em matemática, podemos escrever a composição das funções, f (x) e g (x), ou seja, f (g (x)), como
que pode ser lido como "f composto com g".
Assim, em Haskell, f ∘ g, ou f composto com g, pode ser escrito:
f . g
A composição é associativa, o que significa que f (g (h (x))), escrita com o operador de composição, pode deixar de fora os parênteses sem qualquer ambigüidade.
Ou seja, como (f ∘ g) ∘ h é equivalente af ∘ (g ∘ h), podemos simplesmente escrever f ∘ g ∘ h.
Circulando de volta
Voltando à nossa simplificação anterior, isto:
sumEuler = sum . map_euler . mkList
apenas significa que
sumEuler
é uma composição não aplicada dessas funções:sumEuler = \x -> sum (map_euler (mkList x))
fonte
O operador ponto aplica a função à esquerda (
sum
) à saída da função à direita. No seu caso, você está encadeando várias funções - está passando o resultado demkList
para(map euler)
e, em seguida, passando o resultado disso parasum
. Este site tem uma boa introdução a vários dos conceitos.fonte