it-swarm-pt.tech

Como extrair valor da ação monádica

Existe uma função interna com a assinatura :: (Monad m) => m a -> a?

Hoogle diz que não existe essa função.

Você pode explicar o porquê?

43

Uma mônada fornece apenas duas funções:

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

Ambos retornam algo do tipo m a, então não há como combiná-los de forma alguma para obter uma função do tipo Monad m => m a -> a. Para fazer isso, você precisará de mais do que essas duas funções, portanto, precisará saber mais sobre m do que se trata de uma mônada.

Por exemplo, a mônada Identity possui runIdentity :: Identity a -> a, e várias mônadas têm funções semelhantes, mas não há como fornecê-lo genericamente. De fato, a incapacidade de "escapar" da mônada é essencial para mônadas como IO.

51
hammar

Provavelmente existe uma resposta melhor que essa, mas uma maneira de ver por que você não pode ter um tipo (Monad m) => m a -> a é considerar uma mônada nula:

data Null a = Null

instance Monad Null where
    return a = Null
    ma >>= f = Null

Agora (Monad m) => m a -> a significa Null a -> a, ou seja, obter algo do nada. Você não pode fazer isso.

25
Owen

Isso não existe porque Monad é um padrão para composição, não um padrão para decomposição. Você sempre pode juntar mais peças com a interface que ela define. Não diz nada sobre desmontar nada.

Perguntar por que você não pode tirar algo é como perguntar por que a interface Iterator do Java não contém um método para adicionar elementos ao que está sendo repetido. Simplesmente não é para isso que serve a interface Iterator.

E seus argumentos sobre tipos específicos que possuem um tipo de função de extração seguem exatamente da mesma maneira. Alguma implementação específica de Iterator pode ter uma função add. Mas como não é para isso que Iterator é, a presença desse método em uma instância específica é irrelevante.

E a presença de fromJust é igualmente irrelevante. Não faz parte do comportamento que Monad pretende descrever. Outros deram muitos exemplos de tipos em que não há valor para extract trabalhar. Mas esses tipos ainda suportam a semântica pretendida de Monad. Isso é importante. Isso significa que Monad é uma interface mais geral do que você está creditando.

17
Carl

Suponha que houvesse essa função:

extract :: Monad m => m a -> a

Agora você pode escrever uma "função" como esta:

appendLine :: String -> String
appendLine str = str ++ extract getLine

A menos que a função extract tenha a garantia de nunca terminar, isso violaria a transparência referencial, porque o resultado de appendLine "foo" dependeria de algo diferente de "foo", (b) avalie para valores diferentes quando avaliados em contextos diferentes.

Ou, em palavras mais simples, se houvesse uma operação extract realmente útil, Haskell não seria puramente funcional.

11
Luis Casillas

Existe uma função interna com assinatura :: (Monad m) => m a -> a?

Se o Hoogle disser que não há ... provavelmente não, supondo que sua definição de "incorporado" esteja "nas bibliotecas de base".

Hoogle diz que não existe essa função. Você pode explicar o porquê?

Isso é fácil, porque o Hoogle não encontrou nenhuma função nas bibliotecas base que corresponda ao tipo de assinatura!

Mais seriamente, suponho que você estava pedindo uma explicação monádica. Os problemas são segurança e significando . (Veja também meus pensamentos anteriores sobre magicMonadUnwrap :: Monad m => m a -> a )

Suponha que eu lhe diga que tenho um valor que tem o tipo [Int]. Desde que sabemos que [] é uma mônada, é semelhante a dizer que tenho um valor que tem o tipo Monad m => m Int. Então, vamos supor que você queira obter o Int desse [Int]. Bem, qual Int você deseja? O primeiro? O último? E se o valor que lhe falei for realmente uma lista vazia? Nesse caso, não há nem um Int para lhe dar! Portanto, para as listas, é inseguro tentar extrair um único valor, quer ou não, assim. Mesmo quando é seguro (uma lista não vazia), você precisa de uma função específica da lista (por exemplo, head) para esclarecer o que você quer dizer desejando f :: [Int] -> Int. Espero que você possa intuir a partir daqui que o significado de Monad m => m a -> a simplesmente não está bem definido. Pode ter vários significados para a mesma mônada, ou pode significar absolutamente nada para algumas mônadas e, às vezes, simplesmente não é seguro.

7
Dan Burton

Porque pode não fazer sentido (na verdade, faz não faz sentido em muitos casos).

Por exemplo, eu posso definir um Parser Monad como este:

data Parser a = Parser (String ->[(a, String)])

Agora não há absolutamente nenhuma maneira padrão sensata de obter um String de um Parser String. Na verdade, não há como tirar uma String disso apenas com a Mônada.

6
Cubic

Existe uma função útil extract e algumas outras funções relacionadas a isso em http://hackage.haskell.org/package/comonad-5.0.4/docs/Control-Comonad.html =

Ele é definido apenas para alguns functores/mônadas e não fornece necessariamente a resposta completa, mas fornece uma resposta . Assim, haverá possíveis subclasses de comonad que fornecem etapas intermediárias de escolha da resposta onde você pode controlá-la. Provavelmente relacionado às possíveis subclasses de Traversable. Não sei se essas coisas estão definidas em qualquer lugar.

Por que o hoogle não lista essa função parece ser porque o pacote comonad não está indexado, caso contrário, acho que a restrição da Mônada seria avisada e extract estaria nos resultados para essas Mônadas com um Comonad instância. Talvez isso ocorra porque o analisador hoogle está incompleto e falha em algumas linhas de código.

Minhas respostas alternativas:

  1. você pode executar uma análise de caso - possivelmente recursiva - se tiver importado os construtores do tipo
  2. Você pode reduzir o código que usaria os valores extraídos na mônada usando monad >>= \a -> return $ your code uses a here como uma estrutura de código alternativa e contanto que você possa converter a mônada em "IO ()" de uma maneira que imprima suas saídas. Isso não parece extração, mas matemática não é a mesma do mundo real.
1
codeshot

Bem, tecnicamente, existe nsafePerformIO para a mônada IO.

Mas, como o próprio nome sugere, essa função é ruim e você deve usá-la apenas se você realmente souber o que está fazendo (e se precisar pergunte se você sabe ou não, então você não sabe)

0
hugomg