Pergunta

Eu estou aprendendo sobre mônadas e tenho algumas perguntas.

Este é o lugar onde estou agora. Corrija-me onde estou errado.

  • O símbolo >>= é um operador infix. operadores infixas são funções que tomam dois argumentos (do lado esquerdo e do lado direito lado) e retornam um valor.

  • O símbolo >>= é chamado o operador se ligam e tem assinatura Monad m => m t -> (t -> m u) -> m u. No entanto, os tipos não parecem fazer fila aqui. Nós obter um valor do tipo m t eo segundo argumento é uma função que leva um t. (Eu não vejo como ligar os pontos).

  • Isto deve significar que a função de ligação é de alguma forma capaz de remover a m do m t a fim de obter o t e passá-lo para a função.

Aqui estão as minhas perguntas:

  • É a capacidade de remover o m de m t algo que só é possível dentro de um operador tal ligação. Será que este operador bind têm alguns privilégios especiais ou algo assim?

  • O que isso tem a ver com as mudanças de estado? Eu entendo (eu acho) que o objetivo de mônadas é 'envoltório' efeitos colaterais para que eles sejam isolados do resto do programa. Mas qual é o papel do operador se ligam nisso?

Foi útil?

Solução

É a capacidade de remover o 'M' de 'M t' algo que só é possível dentro de um operador tal ligação. Será que este operador bind têm alguns privilégios especiais ou algo assim?

Bind não é de forma alguma um caso especial, mas geralmente serão definidos no mesmo módulo como o tipo de dados mônadas. Por isso, pode saber sobre (e uso) detalhes que não são exportados pelo módulo. O caso usual seria que o módulo exporta um tipo de dados, mas não a de construtores ou outros detalhes sobre os tipos de estrutura interna. Em seguida, para o código que usa o módulo o funcionamento interno do tipo de dados são invisíveis e que o código não podem modificar directamente os valores deste tipo.

oposta àquela funções definidas dentro do módulo, como por exemplo, alguns ligam >>= operador, o acesso pode o que quiserem a partir do módulo eles são definidos. Então essas funções pode ser capaz de fazer coisas funções "externos" não pode fazer.

Um caso especial é a Mônada IO, uma vez que não está definido por um módulo, mas incorporado no sistema de execução / compilador. Aqui, o compilador sabe sobre os detalhes internos de TI de funções de implementação e expõe como IO de >>=. As implementações dessas funções na verdade são especialmente privilegiada, pois eles vivem "fora do programa", mas este é um caso especial e este fato não deve ser observável a partir de dentro Haskell.

O que isso tem a ver com as mudanças de estado? Eu entendo (eu acho) que o objetivo de mônadas é 'envoltório' efeitos colaterais para que eles sejam isolados do resto do programa. Mas qual é o papel do operador se ligam nisso?

Realmente não precisa ter a ver com mudanças de estado, este é apenas um problema que pode ser tratado com moands. A Mônada IO é usado para ter IO executadas em uma determinada ordem, mas geralmente mônadas são apenas formas de combinar funções em conjunto.

Geralmente um mônade (especificamente a sua função de ligação) define uma forma em que determinadas funções devem ser formada em conjunto com as funções maiores. Este método de combinação de funções é captada no mônade. Como exatamente isso funciona combinando ou por que você iria querer combinar funções de tal forma a não é importante, uma mônada apenas especifica uma maneira de combinar determinadas funções de uma certa maneira. (Veja também esta resposta "Mônadas para programadores C #" , onde repito, basicamente, que algumas vezes com exemplos.)

Outras dicas

é a capacidade de remover o 'H' de 'H t' algo que só é possível dentro de um operador de tal ligação.

Bem, é certamente possível dentro do operador de bind, como seus especifica o tipo:

(>>=) :: m a -> (a -> m b) -> m b

A função 'run' para o seu mônada normalmente pode fazer isso também (para retornar um valor puro de sua computação).

o objetivo de mônadas é a efeitos colaterais 'Wrap' para que eles sejam isolados do resto do programa

Hmm. Não, monads vamos noções modelo de computação. computações-efetuando colaterais são apenas uma tal noção, como é o estado, retrocesso, continuações, a simultaneidade, transações, resultados opcionais, resultados aleatórios, estado revertable, não determinismo ... tudo o que pode ser descrito como uma mônada

A mônada IO é o que você está se referindo, eu assumo. É uma mônada um pouco estranho - ele gera seqüências de mudanças abstratas para o estado do mundo, que são então avaliadas pelo tempo de execução. Bind apenas nos deixa as coisas seqüência na ordem certa no IO mônada - eo compilador, então, traduzir todas essas ações modificadoras mundo seqüenciados em código imperativo que muda que o estado da máquina

.

Isso é muito específico para o IO mônada, porém, não mônadas em geral.

O seguinte é a definição do Monad classe tipo.

class  Monad m  where

    (>>=)       :: forall a b. m a -> (a -> m b) -> m b
    (>>)        :: forall a b. m a -> m b -> m b
    return      :: a -> m a
    fail        :: String -> m a

    m >> k      = m >>= \_ -> k
    fail s      = error s

Cada tipo de instância de Monad classe tipo define a sua própria função >>=. Aqui está um exemplo do tipo de instância Maybe:

instance  Monad Maybe  where

    (Just x) >>= k      = k x
    Nothing  >>= _      = Nothing

    (Just _) >>  k      = k
    Nothing  >>  _      = Nothing

    return              = Just
    fail _              = Nothing

Como podemos ver, porque a versão Maybe de >>= é especialmente definida para entender o Maybe tipo de instância, e porque ele é definido em um lugar que tem acesso legal ao data Maybe a construtores de dados Nothing e Just a, a versão Maybe de >>= é capaz de desembrulhar o a está em Maybe a e passá-las completamente.

Para trabalhar com um exemplo, poderíamos ter:

x :: Maybe Integer
x = do a <- Just 5
       b <- Just (a + 1)
       return b

De-açúcar, o do-notação torna-se:

x :: Maybe Integer
x = Just 5        >>= \a ->
    Just (a + 1)  >>= \b ->
    Just b

que avalia como:

  =                  (\a ->
    Just (a + 1)  >>= \b ->
    Just b) 5

  = Just (5 + 1)  >>= \b ->
    Just b

  =                  (\b ->
    Just b) (5 + 1)

  = Just (5 + 1)

  = Just 6

Os tipos se alinham, curiosamente. Veja como.

Lembre-se que uma mônada é também um functor. A função a seguir é definida para todos os functors:

fmap :: (Functor f) => (a -> b) -> f a -> f b

Agora, a pergunta: Será que estes tipos realmente alinhar? Bem, sim. Dada uma função de a para b, em seguida, se temos um f ambiente em que a está disponível, temos uma f ambiente em que b está disponível.

Por analogia com silogismo:

(Functor Socrates) => (Man -> Mortal) -> Socrates Man -> Socrates Mortal

Agora, como você sabe, uma mônada é um functor equipado com ligar e retorno:

return :: (Monad m) => a -> m a
(=<<) :: (Monad m) => (a -> m b) -> m a -> m b

Você pode não saber que equivalentemente, é um functor equipado com retorno e juntar-se:

join :: (Monad m) => m (m a) -> m a

Veja como estamos descascando uma m. Com um m mônada, você não pode sempre começar a partir m a para a, mas você sempre pode começar a partir m (m a) para m a.

Agora olhe para o primeiro argumento para (=<<). É uma função do tipo (a -> m b). O que acontece quando você passar essa função para fmap? Você começa m a -> m (m b). Assim, "mapeamento" mais de uma m a com um a -> m b função lhe dá m (m b). Observe que este é exatamente como o tipo do argumento para join. Isto não é uma coincidência. A implementação razoável de olhares "ligar" como esta:

(>>=) :: m a -> (a -> m b) -> m b
x >>= f = join (fmap f x)

Na verdade, ligam-se e juntar-se pode ser definido em termos do outro:

join = (>>= id)

I muito recomendar que você lê ( http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html ). Ele dá um perfeito, razão senso comum por que existem mônadas.

Eu entendo (eu acho) que o objetivo de mônadas é 'quebrar' efeitos colaterais para que eles sejam isolados do resto do programa.

É realmente um pouco mais sutil do que isso. Mônadas nos permitem modelar sequenciamento de uma maneira muito geral. Muitas vezes, quando você falar com um especialista de domínio que você encontrá-los dizendo algo como "primeiro nós tentamos X. Então nós tentamos Y, e se isso não funcionar, então nós tentamos Z". Quando você vem para implementar algo como que em uma linguagem convencional você achar que ele não se encaixa, então você tem que lotes de escrita de código extra para cobrir qualquer que seja o especialista de domínio significa a palavra "então".

Em Haskell você pode implementar isso como uma mônada com o "então" traduzido para o operador bind. Assim, por exemplo uma vez eu escrevi um programa onde um item teve que ser atribuído a partir de piscinas de acordo com certas regras. Para o caso 1 que você tirou de piscina X. Se isso estava vazia, então você mudou-se para piscina Y. Para o caso 2, você teve que levá-lo em linha reta da piscina Y. E assim por diante para uma dúzia de casos, incluindo alguns onde você tirou a menos recentemente utilizado a partir de qualquer piscina X ou Y. Eu escrevi um costume mônada especialmente para esse trabalho para que eu pudesse escrever:

case c of
   1: do {try poolX; try poolY}
   2: try poolY
   3: try $ lru [poolX, poolY]

Ele trabalhou muito bem.

É claro que isso inclui os modelos convencionais de sequenciamento. A mônada IO é o modelo que todas as outras linguagens de programação têm; seu justo que em Haskell a uma escolha explícita, em vez de parte do ambiente. A Mônada ST dá-lhe a mutação memória de IO, mas sem a entrada e saída real. Por outro lado a Mônada Estado permite restringir o seu estado para um único valor de um tipo nomeado.

Para algo realmente cérebro flexão, consulte este blog sobre uma mônada estado para trás. O estado propaga na direção oposta à "execução". Se você pensar nisso como como um estado de Mônada executar uma instrução seguido pelo seguinte, em seguida, uma "put" enviará os para trás valor de estado no tempo para qualquer precedente "pegar". O realmente acontece é que uma função mutuamente recursiva fica configurado que só termina se não há paradoxos. Eu não estou completamente certo onde usar tal mônada, mas ilustra o ponto sobre mônadas sendo modelos de computação.

Se você não está pronto para isso, então basta pensar ligamento como um ponto e vírgula sobrecarregável. Que você fica bastante um longo caminho.

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