Comandos de várias linhas no GHCi

134

Estou tendo problemas ao inserir comandos de várias linhas no ghci.

O seguinte código de duas linhas funciona a partir de um arquivo:

addTwo :: Int -> Int -> Int
addTwo x y = x + y

Mas quando entro em ghci, recebo um erro:

<interactive>:1:1: error:
    Variable not in scope: addTwo :: Int -> Int -> Int

Eu também tentei colocar o código dentro :{ ... :}, mas eles também não estão funcionando neste exemplo, porque isso é apenas anexar as linhas em uma linha, o que não deve ser o caso.

Estou usando o WinGHCi, versão 2011.2.0.1

R71
fonte
2
possível duplicata de Como definir uma função em ghci em várias linhas?
devnull 18/05/19

Respostas:

183

Na maioria das vezes, você pode confiar na inferência de tipo para elaborar uma assinatura para você. No seu exemplo, o seguinte é suficiente:

Prelude> let addTwo x y = x + y

Se você realmente deseja uma definição com uma assinatura de tipo ou sua definição se estende por várias linhas, você pode fazer isso em ghci:

Prelude> :{
Prelude| let addTwo :: Int -> Int -> Int
Prelude|     addTwo x y = x + y 
Prelude| :}
Prelude> addTwo 4 7
11

Observe que você também pode compactar isso em uma linha:

Prelude> let addTwo :: Int -> Int -> Int ; addTwo x y = x + y

Você pode descobrir mais sobre como interagir com o ghci na avaliação interativa na seção de prompt da documentação.

Nicolas Wu
fonte
1
Muito obrigado por ambas as soluções. Mas tenho outra pergunta relacionada: por que os quatro espaços em branco necessários são necessários na segunda linha (antes do addTwo)? E isso tem que ser exato, se houver menos ou mais espaços em branco, haverá um erro.
precisa
9
@Rog letinicia um bloco; as entradas em um bloco são agrupadas por recuo; e o primeiro caractere sem espaço em branco em um bloco define o recuo pelo qual eles são agrupados. Como o primeiro caractere que não é um espaço em branco no letbloco acima é o ade addTwo, todas as linhas no bloco devem ser recuadas exatamente tão profundas quanto isso a.
Daniel Wagner
Obrigado. Notei também que em outros blocos let / where. Essa é uma grande diferença de outras línguas em que o espaço em branco é ignorado, então tive algumas dificuldades em entender isso.
R71
124

Resolva esse problema iniciando o GHCI e digitando :set +m:

Prelude> :set +m
Prelude> let addTwo :: Int -> Int -> Int
Prelude|     addTwo x y = x + y
Prelude| 
Prelude> addTwo 1 3
4

Estrondo.


O que está acontecendo aqui (e eu estou falando principalmente com você , pesquisando em busca de ajuda enquanto trabalha no Learn You A Haskell ) é que o GHCI é um ambiente interativo no qual você altera as ligações dos nomes das funções em tempo real. Você precisa agrupar suas definições de função em um letbloco, para que Haskell saiba que você está prestes a definir alguma coisa. O :set +mmaterial é uma abreviação para a construção de :{ código de várias linhas:} .

O espaço em branco também é significativo em blocos, portanto, você deve recuar sua definição de função após a definição de tipo por quatro espaços para contabilizar os quatro espaços em let.

adrian
fonte
5
Tão simples, mas não óbvio. Eu queria gritar com o livro que estava usando por não me dizer isso na página 1!
Tim
2
Em um shell do Linux, echo ':set +m' >> ~/.ghcipara tornar essa configuração persistente.
precisa saber é o seguinte
você pode ter letpor si só na primeira linha, então todo o resto não precisa ser recuado. onde o espaço em branco realmente conta é que não deve haver espaços à direita em suas linhas. o espaço em branco à direita conta como um Enter extra e quebra o bloco de várias linhas.
Will Ness
14

Use let:

Prelude> :{
Prelude| let addTwo :: Int -> Int -> Int
Prelude|     addTwo x y = x + y
Prelude| :}
Prelude> addTwo 2 3
5
Stefan Holdermans
fonte
4

A partir do GHCI versão 8.0.1 , letnão é mais necessário definir funções no REPL.

Portanto, isso deve funcionar bem para você:

λ: addTwo x y = x + y
λ: addTwo 1 2
3
λ: :t addTwo
addTwo :: Num a => a -> a -> a

A inferência de tipo de Haskell fornece digitação generalizada que também funciona para carros alegóricos:

λ: addTwo 2.0 1.0
3.0

Se você precisar fornecer sua própria digitação, parece que precisará usar letcombinado com :set +ma entrada de várias linhas (use para ativar a entrada de várias linhas no GHCI):

λ: let addTwo :: Int -> Int -> Int
 |     addTwo x y = x + y
 | 
λ: addTwo 1 2
3

Mas você receberá erros se tentar passar algo além de uma Intpor causa da sua digitação não polimórfica:

λ: addTwo 2.0 1.0

<interactive>:34:8: error:
     No instance for (Fractional Int) arising from the literal 2.0
     In the first argument of addTwo’, namely 2.0
      In the expression: addTwo 2.0 1.0
      In an equation for it’: it = addTwo 2.0 1.0
Aaron Hall
fonte
2

Para expandir a resposta de Aaron Hall , na versão GHCi 8.4.4, pelo menos, você não precisa usar as letdeclarações de tipo se usar o :{ :}estilo. Isso significa que você não precisa se preocupar em adicionar a indentação de quatro espaços em cada linha subseqüente a ser considerada let, facilitando muito a digitação de funções mais longas ou, em muitos casos, copiar e colar (já que a fonte original provavelmente não terá o recuo correto):

λ: :{
 | addTwo :: Int -> Int -> Int
 | addTwo x y = x + y
 | :}
λ: addTwo 1 2
3

Atualizar

Como alternativa, você pode ativar o modo de entrada de várias linhas com :set +me digitelet por si próprio, pressionar Enter e colar definições sem recuo necessário.

No entanto, isso não parece funcionar com alguns blocos de código, como:

class Box a where
  mkBox :: a -> Boxes.Box

Mas a :{, :}técnica faz.

davidA
fonte
1
na verdade, mesmo antes, você pode digitar :{, em seguida, na próxima linha let, colar suas definições sem recuo adicional e fechar :}. :) e com o modo de entrada de várias linhas definido ( :set +m), você nem precisou dos comandos de chaves, desde que não houvesse espaços à direita nas linhas de código.
Will Ness
Ah, então com :set +mvocê pode usar apenas letna sua própria linha? Então você pode - isso é legal. Obrigado.
davidA
Hmm, eu encontrei alguns casos em que simplesmente digitando letnewline não funciona. Veja minha edição.
davidA