157 votes

Commandes multi-lignes dans GHCi

J'ai des problèmes pour entrer des commandes de plusieurs lignes dans ghci. Le code de 2 lignes suivant fonctionne à partir d'un fichier :

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

Mais quand j'entre dans le ghci, j'obtiens des erreurs. J'ai aussi essayé de mettre le code dans :{ ... :} mais ils ne fonctionnent pas non plus dans cet exemple, car ils ne font qu'ajouter les lignes en une seule, ce qui ne devrait pas être le cas.

J'utilise WinGHCi, version 2011.2.0.1.

2 votes

207voto

Nicolas Wu Points 1890

La plupart du temps, vous pouvez compter sur l'inférence de type pour trouver une signature pour vous. Dans votre exemple, ce qui suit est suffisant :

Prelude> let addTwo x y = x + y

Si vous voulez vraiment une définition avec une signature de type, ou si votre définition s'étend sur plusieurs lignes, vous pouvez le faire dans ghci :

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

Notez que vous pouvez également faire tenir cela sur une seule ligne :

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

Vous pouvez trouver plus d'informations sur l'interaction avec ghci sur le site Web de la Commission européenne. Évaluation interactive à l'invite de la documentation.

1 votes

Merci beaucoup pour ces deux solutions. Mais j'ai une autre question connexe : pourquoi les quatre blancs de tête sont-ils nécessaires dans la deuxième ligne (avant addTwo) ? Et cela doit être exact, s'il y a moins ou plus de blancs, il y a une erreur.

10 votes

@Rog let commence un bloc ; les entrées d'un bloc sont regroupées par indentation ; et le premier caractère sans espace dans un bloc définit l'indentation selon laquelle elles sont regroupées. Puisque le premier caractère sans espace dans le bloc let Le bloc ci-dessus est le a de addTwo toutes les lignes du bloc doivent être indentées exactement à la même profondeur que celle du bloc. a .

0 votes

Merci. J'ai également remarqué cela dans d'autres blocs let/where. C'est une grande différence par rapport à d'autres langues où les espaces blancs sont ignorés, et j'ai donc eu quelques difficultés à comprendre cela.

143voto

rockist Points 301

Résolvez ce problème en lançant GHCI et en tapant :set +m :

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

Boom.


Ce qui se passe ici (et je parle surtout à vous une personne qui cherche de l'aide sur Internet pendant que vous travaillez sur votre chemin Apprendre un Haskell ) est que GHCI est un environnement interactif dans lequel vous modifiez les liaisons des noms de fonctions à la volée. Vous devez envelopper vos définitions de fonctions dans une balise let afin que Haskell sache que vous êtes sur le point de définir quelque chose. Le site :set +m est un raccourci pour l'expression multi-ligne :{ code :} construire.

L'espace blanc est également important dans les blocs, de sorte que vous devez indenter votre définition de fonction après votre définition de type de quatre espaces pour tenir compte des quatre espaces de l'élément let .

5 votes

C'est si simple, mais pas évident. J'avais envie de crier sur le livre que j'utilisais pour ne pas me dire ça en page 1 !

6 votes

Depuis un shell Linux, echo ':set +m' >> ~/.ghci pour rendre ce paramètre persistant.

1 votes

Vous pouvez avoir let Là où l'espace blanc compte vraiment, c'est qu'il ne doit pas y avoir d'espace de queue sur vos lignes. L'espace blanc de queue compte comme une entrée supplémentaire et rompt le bloc de plusieurs lignes.

15voto

dblhelix Points 5042

Utilisez let :

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

6voto

meowsqueak Points 2131

Pour développer Réponse d'Aaron Hall Dans la version GHCi 8.4.4 au moins, il n'est pas nécessaire d'utiliser la commande let avec les déclarations de type si vous utilisez l'option :{ :} le style. Cela signifie que vous n'avez pas à vous préoccuper d'ajouter l'indentation de 4 espaces sur chaque ligne suivante pour tenir compte des éléments suivants let Les fonctions plus longues sont ainsi beaucoup plus faciles à taper ou, dans de nombreux cas, à copier-coller (puisque la source originale n'a probablement pas l'indentation correcte) :

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

Mise à jour

Comme alternative, vous pouvez activer le mode d'entrée multi-ligne avec :set +m puis tapez let seul, appuyez sur Entrée, puis collez les définitions sans indentation.

Cependant, cela ne semble pas fonctionner avec certains blocs de code, tels que :

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

Mais le :{ , :} technique le fait.

1 votes

En fait, même avant, vous pouviez taper :{ puis sur la ligne suivante let par lui-même, puis collez vos définitions sans ajouter d'indentation, puis fermez avec :} . :) et avec le mode d'entrée multi-ligne réglé ( :set +m ), vous n'aviez même pas besoin des commandes entre accolades tant qu'il n'y avait pas d'espace à la fin des lignes de code.

0 votes

Ah, donc avec :set +m vous pouvez simplement utiliser let sur sa propre ligne ? Donc vous pouvez - c'est cool. Merci.

0 votes

Hmm, j'ai trouvé des cas où le simple fait de taper let alors la nouvelle ligne ne fonctionne pas. Voir mon édition.

5voto

Aaron Hall Points 7381

A partir de GHCI version 8.0.1 , let n'est plus nécessaire pour définir des fonctions sur le REPL.

Cela devrait donc fonctionner correctement pour vous :

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

L'inférence de type de Haskell fournit un typage généralisé qui fonctionne également pour les flottants :

: addTwo 2.0 1.0
3.0

Si vous devez fournir votre propre typage, il semble que vous deviez utiliser let combiné avec une entrée multiligne (utiliser :set +m pour activer l'entrée multiligne dans GHCI) :

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

Mais vous obtiendrez des erreurs si vous essayez de passer autre chose qu'un Int à cause de votre typage non polymorphe :

: 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X