¿Cómo definir una función en ghci a través de múltiples líneas?

161

Estoy tratando de definir cualquier función simple que abarque varias líneas en ghci, tome lo siguiente como ejemplo:

let abs n | n >= 0 = n
          | otherwise = -n

Hasta ahora he intentado presionar Enter después de la primera línea:

Prelude> let abs n | n >= 0 = n
Prelude>           | otherwise = -n
<interactive>:1:0: parse error on input `|'

También intenté usar los comandos :{y :}pero no llego lejos:

Prelude> :{
unknown command ':{'
use :? for help.

Estoy usando GHC Interactive versión 6.6 para Haskell 98 en Linux, ¿qué me estoy perdiendo?

Peter McG
fuente
20
Actualice su instalación de GHC. ¡GHC 6.6 tiene casi 5 años! Las últimas versiones de Haskell están aquí: haskell.org/platform
Don Stewart
posible duplicado de comandos
mmmmmm
1
@ Mark Este OP ya probó las soluciones a ese problema. Este problema se debe a un ghci desactualizado, no a la falta de conocimiento sobre qué hacer. Solución aquí: actualización. Solución ahí: el uso :{, :}.
AndrewC

Respuestas:

124

Para los guardias (como su ejemplo), puede ponerlos todos en una línea y funciona (a los guardias no les importa el espaciado)

let abs n | n >= 0 = n | otherwise = -n

Si desea escribir su función con múltiples definiciones que coincidan con el patrón en los argumentos, así:

fact 0 = 1
fact n = n * fact (n-1)

Luego usaría llaves con punto y coma que separan las definiciones

let { fact 0 = 1 ; fact n = n * fact (n-1) }
newacct
fuente
258

GHCi ahora tiene un modo de entrada multilínea, habilitado con: set + m. Por ejemplo,

Prelude> :set +m
Prelude> let fac 0 = 1
Prelude|     fac n = n * fac (n-1)
Prelude|
Prelude> fac 10
3628800
karakfa
fuente
39
Establecer el modo multilínea hace que ghcise parezca mucho al intérprete de Python a este respecto. ¡Muy conveniente! De hecho, puede crear un .ghciarchivo en su directorio de inicio en el que lo coloque :set +my el modo multilínea se convertirá en el predeterminado cada vez que comience ghci.
kqr
2
Esto es realmente asombroso. Pero me he dado cuenta de que cuando configuro mi mensaje usando :set prompt "λ "las líneas continuas dicen en Preludelugar de λ. ¿Alguna forma de evitar esto?
abhillman
2
Consulte aquí el parche para definir un nuevo mensaje de continuación ghc.haskell.org/trac/ghc/ticket/7509#no1
karakfa
44
Para evitar que aparezca Preludio en las líneas de continuación, agregue también: configure prompt2 "|" en su .ghci.
Nick
12
Puede evitar completamente la sangría utilizando un seguimiento let. Simplemente escriba un letseguido de una nueva línea: let⏎. Entonces fac 0 = 1⏎. Entonces fac n = n * fac (n-1)⏎ ⏎ y listo!
Iceland_jack
62

Dan es correcta, pero :{y :}debe aparecer cada uno en su propia línea:

> :{ 
> let foo a b = a +
>           b
> :}
> :t foo
foo :: (Num a) => a -> a -> a

Esto también interactúa con la regla de diseño, por lo que cuando se usa la notación de do puede ser más fácil usar llaves y punto y coma explícitamente. Por ejemplo, esta definición falla:

> :{
| let prRev = do
|   inp <- getLine
|   putStrLn $ reverse inp
| :}
<interactive>:1:18:
    The last statement in a 'do' construct must be an expression

Pero funciona cuando se agregan llaves y punto y coma:

> :{
| let prRev = do {
|   inp <- getLine;
|   putStrLn $ reverse inp;
| }
| :}
> :t prRev
prRev :: IO ()

Esto solo importará realmente cuando pegue definiciones de un archivo, donde la sangría podría cambiar.

Justin Bailey
fuente
Esto no funciona si tiene una línea que termina en '=' (con la definición siguiente en la siguiente línea), al menos en la versión 7.6.3.
AdamC
1
¿Quizás esto falla, porque la segunda y tercera línea del let no tienen sangría suficiente ...? (Dos espacios más.)
Evi1M4chine
7

Si no desea actualizar GHC solo por :{y :}, deberá escribirlo todo en una línea:

> let abs' n | n >= 0 = n | otherwise = -n

No conozco ninguna definición única en Haskell que deba escribirse en varias líneas. Lo anterior sí funciona en GHCi:

> :t abs'
abs' :: (Num a, Ord a) => a -> a

Para otras expresiones, como los dobloques, deberá usar la sintaxis sin diseño con llaves y punto y coma (eugh).

CA McCann
fuente
0

Estoy usando GHCi, versión 8.2.1 en macOS Catalina 10.15.2. Lo siguiente es cómo pongo juntos la declaración de tipo de función y los guardias. Tenga en cuenta que las barras verticales a la izquierda son para líneas múltiples de GHCi.

λ: let abs' :: (Num a, Ord a) => a -> a
 |     abs' n | n >= 0 = n | otherwise = -n
 | 
λ: abs' 7
7
λ: abs' (-7)
7
Pulgar dorado
fuente
1
Si usa :{y :}no necesita especificar let antes de su declaración de tipo, lo que significa que no necesita sangrar la segunda línea y las siguientes.
davidA
Muchas gracias davidA. Eso es exactamente lo que había estado buscando pero no pude encontrar.
Golden Thumb
0

Parece que pegar ambas líneas a la vez o usar control-enter para cada nueva línea lo mantiene todo junto, al menos en https://repl.it/languages/haskell . Verás 2 puntos al comienzo de la segunda línea. O póngalo en un archivo y: cargue el archivo (: l main). ¿Cómo es que los abdominales no funcionan con números negativos? Oh, tienes que poner paréntesis alrededor del número.

   let abs n | n >= 0 = n 
..           | otherwise = -n
   abs (-1)
js2010
fuente