Por que acessar o System.Info não é considerado uma operação de E / S no Haskell?

25

No módulo System.Info, vejo estas funções:

os :: String
arch :: String
compilerName :: String
compilerVersion :: Version

Por que não há IOlá? Eles estão acessando o sistema ... Estou errado? Minha expectativa era algo como:

os :: IO String
arch :: IO String
compilerName :: IO String
compilerVersion :: IO Version

Caso de uso:

      print os            -- "darwin"
      print arch          -- "x86_64"
      print compilerName  -- "ghc"
Francisco Albert
fonte

Respostas:

29

Você não está recebendo essas informações em tempo de execução . Eles são codificados no compilador, conforme instalado no seu sistema.

Isso é mais óbvio se você olhar para a definição compilerNameencontrada em http://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html .

compilerName :: String
compilerName = "ghc"

mas até algo como os

os :: String
os = HOST_OS

é definido em termos de um nome indefinido HOST_OS(um valor começando com uma letra maiúscula ??) que sugere que é apenas um espaço reservado que é substituído durante a instalação.

Alguém também pode me corrigir (por favor!), Mas o {-# LANGUAGE CPP #-}pragma na parte superior desse arquivo sugere que HOST_OSessas coisas são substituídas por seqüências apropriadas pelo pré-processador C antes da compilação.

chepner
fonte
2
Se o OP realmente quer alguma IOlá, há um invólucro em torno uname(3)acessível em Hackage: hackage.haskell.org/package/bindings-uname
thsutton
19

A pergunta é boa. A resposta, como é, é que esses valores são estáticos por compilação do programa. Eles são essencialmente compilados no programa e nunca mudam depois disso. Como tal, nada (nas suposições que o GHC usa) quebra se você as tratar como constantes. E é mais conveniente usar uma constante simples do que uma ação de E / S.

Mas esse é todo o tipo de raciocínio legado. Haskell é um idioma antigo. (Não, na verdade, é mais antigo que Java há vários anos.) Muitas bibliotecas foram construídas com um raciocínio que não é mais considerado uma prática recomendada. Estes são exemplos disso. Uma biblioteca moderna que os expõe provavelmente faria ações de IO, mesmo que os resultados não sejam alterados após a compilação. É mais útil colocar coisas que não são constantes no nível de origem por trás das ações de E / S, embora ainda existam algumas exceções notáveis, como Intalterar o tamanho entre plataformas de 32 e 64 bits.

De qualquer forma ... eu diria que suas expectativas são sólidas e esses tipos são resultados de esquisitices históricas.

Carl
fonte
-9

EDIT: Obrigado a @interjay e @Antal Spector-Zabusky por explicar por que esta resposta está sendo votada abaixo. Eles escreveram

A documentação é um pouco enganadora. Os valores são codificados no compilador GHC. Após 48 anos, você certamente sabe que o código real sempre supera a documentação. - interjay ontem @ andy256 Você está absolutamente certo de que a documentação está ruim (de fato, é parte do motivo pelo qual Francisco fez essa pergunta em primeiro lugar) e sua confusão é compreensível. O problema de Haskell é que, se esses valores de String pudessem variar em tempo de execução, isso seria um erro flagrante - as variáveis ​​não podem mudar. Esse é o significado do construtor do tipo IO - ele representa uma computação que tem permissão para acessar o "mundo exterior" e, portanto, um cujo resultado pode mudar. Fazer uma chamada do sistema é um bom exemplo de uma ação de E / S. … [1/2] - Antal Spector-Zabusky 9 horas atrás @ andy256… (Outra ação de IO pode ser "atualizar um contador global".) Portanto, quando vemos uma String, sabemos que ela não pode fazer nenhuma comunicação com o sistema operacional sob o capô. É por isso que, talvez surpreendentemente, se você não está acostumado ao Haskell, não seria fácil implementar o os :: String para fazer uma chamada do sistema - qualquer valor desse tipo não é implementável no Haskell básico, violaria a expectativa de todos os programadores de como os programas trabalhar e até potencialmente desarmar o compilador e o otimizador (não é uma preocupação teórica - existem respostas do Stack Overflow em que as pessoas encontram problemas análogos). [2/2] - Antal Spector-Zabusky É por isso que, talvez surpreendentemente, se você não está acostumado ao Haskell, não seria fácil implementar o os :: String para fazer uma chamada do sistema - qualquer valor desse tipo não é implementável no Haskell básico, violaria a expectativa de todos os programadores de como os programas trabalhar e até potencialmente desarmar o compilador e o otimizador (não é uma preocupação teórica - existem respostas do Stack Overflow em que as pessoas encontram problemas análogos). [2/2] - Antal Spector-Zabusky É por isso que, talvez surpreendentemente, se você não está acostumado ao Haskell, não seria fácil implementar o os :: String para fazer uma chamada do sistema - qualquer valor desse tipo não é implementável no Haskell básico, violaria a expectativa de todos os programadores de como os programas trabalho e, potencialmente, até desarmar o compilador e o otimizador (não é uma preocupação teórica - existem respostas do Stack Overflow em que as pessoas enfrentam problemas análogos). [2/2] - Antal Spector-Zabusky e potencialmente até desativa o compilador e o otimizador (não é uma preocupação teórica - existem respostas do Stack Overflow em que as pessoas encontram problemas análogos). [2/2] - Antal Spector-Zabusky e potencialmente até desativa o compilador e o otimizador (não é uma preocupação teórica - existem respostas do Stack Overflow em que as pessoas encontram problemas análogos). [2/2] - Antal Spector-Zabusky

Atualmente, possui dois votos para exclusão. Deixarei que esse processo siga seu curso, mas sugiro que realmente tenha algum valor. Em uma nota lateral, suas explicações mostram que a pergunta era fraca, e também as respostas, pois um novato em Haskell poderia facilmente seguir o raciocínio que eu fiz.

Resposta original:

Eu não sou um programador Haskell, mas as duas respostas já dadas não correspondem à documentação que o OP vinculou.

Minha interpretação da documentação segue.

os :: String - Isso fornece "O sistema operacional no qual o programa está sendo executado".

Espero que isso emita uma chamada do sistema para obter as informações. Como o sistema no qual o programa é compilado pode ser diferente daquele em que é executado, não pode ser um valor inserido pelo compilador. Se o código estiver sendo interpretado, o intérprete poderá fornecer o resultado, que deve ser obtido por meio de uma chamada do sistema.

arch :: String - Isso fornece "A arquitetura da máquina na qual o programa está sendo executado".

Novamente, espero que isso faça uma chamada do sistema para obter as informações. Como o sistema no qual o programa é compilado pode ser diferente daquele em que é executado, não pode ser um valor inserido pelo compilador.

compilerName :: String - Isso fornece "A implementação do Haskell com a qual o programa foi compilado ou está sendo interpretado".

Este valor é certamente inserido pelo compilador / intérprete.

compilerVersion :: String- Isso fornece "A versão compilerNamecom a qual o programa foi compilado ou está sendo interpretado".

Este valor é certamente inserido pelo compilador / intérprete.

Embora você considere a obtenção da entrada das duas primeiras chamadas, o resultado vem dos valores mantidos pelo sistema operacional. E / S geralmente se refere ao acesso ao armazenamento secundário.

andy256
fonte
3
Não é verdade para o haskell. Aqui, qualquer cálculo não é ordenado e seu resultado pode ser armazenado em cache. As funções são puras, portanto, se uma função não aceita argumentos, é muito parecida com uma constante. As funções de um argumento parecem apenas hashmaps ou dicionários, que calculam o valor com base na chave. Você não pode usar ambiente externo, fazer chamadas em tais funções, nem mesmo obter um número aleatório ou data atual. Mas se você realmente quiser usar esse "sequenciamento", ou ambiente, então você precisa usar IOmônada para emular o estado, emular a sequência de operações
Yuri Kovalenko
"Você não pode usar ambiente externo, faça syscalls em tais funções" - Claro que pode, especialmente se "você" é o compilador Haskell! Seria muito fácil para uma implementação Haskell implementar, para os :: Stringque ele faça uma chamada de sistema quando for avaliada.
quer
2
Acho que você não entende o significado da mônada de IO em Haskell.
Sneftel
@ Sneftel Você está certo, é claro. Eu escolhi responder porque, após 48 anos de programação em todos os paradigmas e escrevendo o compilador ímpar, as respostas iniciais não correspondiam à documentação e ainda não. Diz claramente isso ose archsão obtidos em tempo de execução.
andy256
11
A documentação é um pouco enganadora. Os valores são codificados no compilador GHC. Após 48 anos, você certamente sabe que o código real sempre supera a documentação.
interjay