Recentemente, estou tentando usar o Haskell em alguns dos meus sistemas de produção de casos reais. O sistema do tipo Haskell realmente me oferece uma grande ajuda. Por exemplo, quando percebi que preciso de alguma função do tipo
f :: (Foldable t, Monad m) => ( a-> b -> m b) -> b -> t a -> m b
Na verdade, existem funções como foldM
, foldlM
e foldrM
.
No entanto, o que realmente me chocou é a definição dessas funções, como:
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldr f' return xs z0
where f' x k z = f z x >>= k
portanto, a função f'
deve ser do tipo:
f' :: a -> b -> b
conforme exigido por foldr
, então b
deve ser do tipo *-> m *
, para que toda a definição de foldlM
faça sentido.
Outro exemplo inclui definições de liftA2
e<*>
(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 id
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x = (<*>) (fmap f x)
Eu tentei algumas das minhas próprias soluções antes de espreitar o código fonte. Mas a diferença é tão grande que acho que nunca poderia encontrar essa solução, independentemente de quantas linhas de código escreverei no futuro.
Portanto, minha pergunta é: que tipo de conhecimento ou qual ramo específico da matemática é necessário para alguém raciocinar em um nível tão abstrato.
Eu sei que a teoria das categorias pode oferecer alguma ajuda e eu acompanho esta ótima palestra há muito tempo e ainda estou trabalhando nela.
fonte
Respostas:
Em geral, lógica etc., eu imaginaria. Mas você também pode aprender fazendo isso. :) Com o tempo, você percebe alguns padrões, aprenda alguns truques.
Assim
foldr
com um argumento extra. Alguns vêem isso como dobrar em funções para que possam ser combinadas.
eid
(que às vezes são reais<=<
ereturn
),Alguns acham mais fácil entendê-lo em termos mais simples e sintáticos, como
portanto, quando
g
não for rigoroso em seu segundo argumento,s
pode servir como um estado transmitido da esquerda, embora estejamos dobrando à direita, como um exemplo.fonte
Portanto, a melhor maneira de entender é fazendo isso. Abaixo há uma implementação de
foldlM
usar emfoldl
vez defoldr
. É um bom exercício, tente e chegue mais tarde à solução que eu sugiro. O exemplo explica todo o raciocínio que eu fiz para alcançá-lo, que pode ser diferente do seu e pode ser tendencioso, porque eu já sabia sobre o uso de um acumulador de funções.Etapa 1 : vamos tentar escrever
foldlM
em termos defoldl
Aqui você percebe que isso
f'
é puro e precisa extrair o resultadof
para digitar match. A única maneira de 'extrair' um valor monádico é com o>>=
operador, mas esse operador precisa ser quebrado logo após ser usado.Então, como conclusão: toda vez que você terminar, eu gostaria de desembrulhar completamente essa mônada , desista. Não é o caminho certo
Etapa 2 : vamos tentar escrever
foldlM
em termos de,foldl
mas primeiro usar[]
como dobrável, já que é fácil padronizar a correspondência (ou seja, na verdade, não precisamos usarfold
)Ok, isso foi fácil. Vamos comparar a definição com a
foldl
definição usual para listasLegal!! eles são praticamente iguais. O caso trivial é exatamente a mesma coisa. O caso recursivo é um pouco diferente, você gostaria de escrever algo mais parecido com:
foldlM' f (f z0 x) xs
. Mas não é compilado como na etapa 1, então você pode pensar OK, não quero aplicarf
, apenas para manter tal cálculo e compor com ele>>=
. Eu gostaria de escrever algo mais comofoldlM' f (f z0 x >>=) xs
se tivesse sentido ...Etapa 3 Perceba que o que você deseja acumular é uma composição de função e não um resultado. ( aqui estou provavelmente tendencioso pelo fato de já saber porque você o postou ).
Pelo tipo
initFunc
e uso de nosso conhecimento da etapa 2 (a definição recursiva), podemos deduzir issoinitFunc = return
. A definição def'
pode ser concluída sabendo quef'
deve usarf
e>>=
.Como você pode ver, não é tão difícil fazê-lo. Precisa de prática, mas não sou um desenvolvedor profissional de haskell e poderia fazer isso sozinho, é uma questão de prática
fonte
Monad
instâncias típicas .Você não precisa de nenhum conhecimento específico em matemática para escrever uma função como
foldM
. Estou usando Haskell em produção há 4 anos e também estou lutando para entender essa definição defoldM
. Mas isso é principalmente porque está mal escrito. Por favor, não tome isso como uma falha pessoal se você não conseguir entender algum código obscuro. Aqui está uma versão mais legível dofoldlM
Esta função ainda não é a mais fácil. Principalmente porque tem uso não típico de
foldr
onde o acumulador intermediário é uma função. Mas você pode ver alguns exemplos que tornam essa definição mais legível:where
(para que você saiba a forma dos argumentos).Depois de ver essa função, agora você pode executar a técnica de raciocínio equacional para expandir a definição passo a passo e ver como ela funciona. A capacidade de criar essas funções vem com a experiência. Não tenho fortes habilidades matemáticas e essa função não é uma função típica de Haskell. Mas quanto mais prática você tiver, melhor fica :)
fonte