Comandi multilinea in GHCi


134

Sto riscontrando problemi nell'inserimento di comandi multilinea in ghci.

Il seguente codice a 2 righe funziona da un file:

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

Ma quando entro in ghci, ricevo un errore:

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

Ho anche provato a inserire il codice all'interno :{ ... :}, ma non funzionano anche per questo esempio, perché questo sta semplicemente aggiungendo le righe in una riga, il che non dovrebbe essere il caso.

Sto usando WinGHCi, versione 2011.2.0.1


Risposte:


183

Il più delle volte, puoi fare affidamento sull'inferenza del tipo per elaborare una firma per te. Nel tuo esempio, è sufficiente quanto segue:

Prelude> let addTwo x y = x + y

Se vuoi davvero una definizione con una firma di tipo, o la tua definizione si estende su più righe, puoi farlo in ghci:

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

Nota che puoi anche comprimerlo su una riga:

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

Puoi scoprire di più sull'interazione con ghci nella valutazione interattiva nella sezione prompt della documentazione.


1
Grazie mille per entrambe le soluzioni. Ma ho un'altra domanda correlata: perché i quattro spazi vuoti principali sono richiesti nella seconda riga (prima di aggiungere due)? E questo deve essere esatto, se ci sono meno o più spazi vuoti, allora c'è un errore.
R71,

9
@Rog letinizia un blocco; le voci in un blocco sono raggruppate per rientro; e il primo carattere non bianco in un blocco imposta il rientro in base al quale sono raggruppati. Poiché il primo carattere non di spazi bianchi nel letblocco sopra è il adi addTwo, tutte le righe nel blocco devono essere rientrate con la stessa profondità a.
Daniel Wagner,

Grazie. Ho anche notato che in altri blocchi let / where. Questa è una grande differenza rispetto ad altre lingue in cui lo spazio bianco viene ignorato, quindi ho avuto qualche difficoltà a comprenderlo.
R71,

124

Risolvi questo problema accendendo 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

Boom.


Quello che sta succedendo qui (e sto parlando principalmente con te , persona che cerca su Google mentre ti fai strada attraverso Learn You A Haskell ) è che GHCI è un ambiente interattivo in cui stai cambiando i collegamenti dei nomi delle funzioni al volo. Devi racchiudere le definizioni delle funzioni in un letblocco, in modo che Haskell sappia che stai per definire qualcosa. Il :set +mmateriale è una scorciatoia per il costrutto del :{ codice multilinea :}.

Anche lo spazio bianco è significativo in blocchi, quindi è necessario rientrare la definizione della funzione dopo la definizione del tipo di quattro spazi per tenere conto dei quattro spazi in let.


5
Così semplice, ma non ovvio. Volevo urlare al libro che stavo usando per non dirmelo a pagina 1!
Tim

2
Da una shell Linux, echo ':set +m' >> ~/.ghciper rendere persistente questa impostazione.
truthadjustr,

puoi avere letda solo sulla prima riga, quindi tutto il resto non ha bisogno di essere rientrato affatto. dove lo spazio bianco conta davvero è che non ci devono essere spazi finali sulle linee. lo spazio bianco finale viene conteggiato come Invio aggiuntivo e interrompe il blocco multilinea.
Will Ness,

14

Utilizzare let:

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

4

A partire dalla versione 8.0.1 di GHCI , letnon è più necessario definire le funzioni sul REPL.

Quindi questo dovrebbe funzionare bene per te:

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

L'inferenza di tipo di Haskell fornisce una tipizzazione generalizzata che funziona anche per i float:

λ: addTwo 2.0 1.0
3.0

Se è necessario fornire la propria digitazione, sembra che sia necessario utilizzare in letcombinazione con l'input multilinea (utilizzare :set +mper abilitare l'input multilinea in GHCI):

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

Ma otterrai errori se provi a passare qualsiasi cosa tranne una a Intcausa della tua digitazione non polimorfica:

λ: 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

2

Per espandere la risposta di Aaron Hall , almeno nella versione GHCi 8.4.4, non è necessario utilizzare le letdichiarazioni di tipo se si utilizza lo :{ :}stile. Ciò significa che non devi preoccuparti di aggiungere il rientro di 4 spazi su ogni riga successiva da tenere in considerazione let, rendendo le funzioni più lunghe molto più facili da digitare o, in molti casi, copia-incolla (poiché la fonte originale probabilmente non avrà il rientro corretto):

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

Aggiornare

In alternativa è possibile attivare la modalità di input su più righe con :set +m, quindi digitare letautonomamente, premere Invio, quindi incollare le definizioni senza necessità di rientro.

Tuttavia, questo non sembra funzionare con alcuni blocchi di codice, come:

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

Ma il :{, :}tecnica fa.


1
in realtà, anche prima, potresti digitare :{, quindi sulla riga successiva letda solo, quindi incollare le tue definizioni senza alcun rientro aggiunto, quindi chiudere :}. :) e con la modalità di input multi-linea impostata ( :set +m) non hai nemmeno bisogno dei comandi parentesi graffe fintanto che non ci sono spazi finali sulle linee di codice.
Will Ness,

Ah, quindi con :set +mte puoi semplicemente usarlo letsulla sua stessa linea? Quindi puoi - è fantastico. Grazie.
David,

Hmm, ho trovato alcuni casi in cui semplicemente digitando letNewline non funziona. Vedi la mia modifica.
David,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.