GHCiの複数行コマンド


134

ghciで複数行のコマンドを入力する際に​​問題があります。

次の2行のコードはファイルから機能します。

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

しかし、ghciと入力すると、エラーが発生します。

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

私もコードを:{ ... :}に入れてみましたが、これは行を1行に追加するだけなので、この例では機能しません。

WinGHCiバージョン2011.2.0.1を使用しています


回答:


183

ほとんどの場合、型推論に頼って署名を作成できます。あなたの例では、以下で十分です:

Prelude> let addTwo x y = x + y

型シグネチャを持つ定義が本当に必要な場合、または定義が複数行にわたる場合は、ghciでこれを行うことができます。

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

これを1行にまとめることもできます。

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

ドキュメントのプロンプトセクションにあるインタラクティブ評価で ghciとのやり取りの詳細を確認できます。


1
両方の解決策をありがとうございました。しかし、別の関連する質問があります。2行目(addTwoの前)に4つの先行ブランクが必要なのはなぜですか。そしてこれは正確でなければなりません、もしブランクが少ないか多いなら、エラーがあります。
R71

9
@Rog letはブロックを開始します。ブロック内のエントリはインデントでグループ化されています。また、ブロック内の最初の非空白文字は、それらをグループ化するためのインデントを設定します。let上記のブロックの最初の空白以外の文字はaof addTwoであるため、ブロック内のすべての行はそれと同じ深さでインデントする必要がありますa
Daniel Wagner、

ありがとう。他のlet / whereブロックでもそのことに気づきました。これは空白が無視される他の言語との大きな違いであり、それを理解するのは少し困難でした。
R71

124

この問題を解決するには、GHCIを起動して次のように入力します:set +m

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

ブーム。


ここで何が起こっているのか(そして私は主にあなたと話していますLearn You A Haskellを進めながら助けを求めてグーグルする人)GHCIは関数名のバインディングをその場で変更しているインタラクティブな環境です。関数定義をletブロックにラップして、Haskellが何かを定義しようとしていることを認識できるようにする必要があります。これら:set +mは、複数行の:{ コード :}構成の省略形です。

空白はブロックでも重要であるため、型定義の後に関数定義を4つのスペースでインデントして、の4つのスペースを考慮する必要がありますlet


5
とてもシンプルですが、明白ではありません。私は1ページでそのことを私に言わなかったために使用していた本で叫びたくなりました!
Tim

2
Linuxシェルから、echo ':set +m' >> ~/.ghciこの設定を永続化するには。
TruthAdjuster 2018年

let最初の行に単独で置くことができ、残りはすべてインデントする必要がありません。空白が本当に重要なのは、行の末尾にスペースがないことです。末尾の空白は余分なEnterとして数えられ、複数行のブロックを改行します。
ネスは


4

以下のようGHCiのバージョン8.0.1letもはやREPLに関数を定義する必要はありません。

だからこれはあなたのためにうまくいくはずです:

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

Haskellの型推論は、浮動小数点に対しても機能する一般化された型付けを提供します。

λ: addTwo 2.0 1.0
3.0

独自のタイピングを提供する必要がある場合letは、複数行入力と組み合わせて使用する必要があるようです(:set +mGHCIで複数行入力を有効にするために使用)。

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

しかし、Intポリモーフィックでない型付けのために何かを渡そうとすると、エラーが発生します。

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

アーロンホールの回答を拡張するには、少なくともバージョンGHCi 8.4.4ではlet:{ :}スタイルを使用する場合、型宣言で使用する必要はありません。つまり、以降のすべての行に4スペースのインデントを追加して考慮する必要がletなく、長い関数を入力しやすくなります。多くの場合、コピーして貼り付けることができます(元のソースにはおそらくないため)正しいインデント):

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

更新

別の方法として、で複数行入力モードをオンにしてから:set +m、それlet自体を入力してEnterキーを押し、インデントを必要とせずに定義を貼り付けることができます。

ただし、これは次のような一部のコードブロックでは機能しないようです。

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

しかし:{:}テクニックはそうです。


1
実際には、以前でも、と入力:{し、次の行letを単独で入力し、インデントを一切追加せずに定義を貼り付けてから、で閉じることができ:}ます。:)および複数行入力モードセット(:set +m)を使用すると、コード行に末尾のスペースがない限り、中括弧コマンドも必要ありませんでした。
ネスは

ああ、それで:set +mあなたはlet自分のラインで使うことができますか?だからできる-それはクールだ。ありがとうございました。
davidA

うーん、単にlet改行してから改行を入力しても機能しない場合があります。私の編集を参照してください。
davidA
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.