複数の行にまたがるghciで関数を定義する方法は?


161

ghciで複数の行にまたがる単純な関数を定義しようとしています。例として次のようにします。

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

これまでのところ、最初の行の後でEnterキーを押してみました。

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

また、:{and :}コマンドを使用しようとしましたが、遠くまで行きません:

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

LinuxのHaskell 98でGHC Interactiveバージョン6.6を使用していますが、何が欠けていますか?


20
GHCインストールをアップグレードしてください。GHC 6.6はほぼ5年前のものです。Haskellの最新バージョンはこちら:haskell.org/platform
Don Stewart


1
@MarkこのOPはすでにその問題の解決策を試しました。この問題は古いghciが原因であり、何をすべきかについての知識の欠如ではありません。ここでの解決策:アップグレード。そこでの解決策:、を使用:{:}ます。
AndrewC 2014年

回答:


124

(例のように)ガードの場合、それらをすべて1行に置くだけで機能します(ガードは間隔を気にしません)

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

次のように、引数にパターンマッチする複数の定義を使用して関数を記述したい場合:

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

次に、定義をセミコロンで区切って中括弧を使用します

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

258

GHCiにマルチライン入力モードが追加され、:set + mで有効になりました。例えば、

Prelude> :set +m
Prelude> let fac 0 = 1
Prelude|     fac n = n * fac (n-1)
Prelude|
Prelude> fac 10
3628800

39
ghciこの点で、複数行モードを設定すると、Pythonインタープリターのように動作します。とても便利!実際に.ghciは、ホームディレクトリにファイルを作成できます。このファイルを置く:set +mと、起動するたびにマルチラインモードがデフォルトになりますghci
kqr 2013年

2
これは本当に素晴らしいです。しかし、私はプロンプトを設定するときに:set prompt "λ "、継続された行を使用してのPrelude代わりに言うことに気付きましたλ。これを回避する方法はありますか?
abhillman 2014年

2
新しい継続プロンプトを定義するパッチについては、ここを参照してくださいghc.haskell.org/trac/ghc/ticket/7509#no1
karakfa

4
Preludeが継続行に表示されないようにするには、.ghciに:set prompt2 "|"も追加します。
Nick

12
末尾を使用すると、インデントを完全に回避できletます。単にaを入力し、letその後に改行を続けますlet。その後、fac 0 = 1⏎。その後、fac n = n * fac (n-1)⏎⏎以上で完了です。
Iceland_jack 2016

62

ダンは正しいですが:{:}それぞれが独自の行に表示される必要があります。

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

これはレイアウトルールとも相互作用するため、do表記を使用する場合は、中括弧とセミコロンを明示的に使用する方が簡単な場合があります。たとえば、次の定義は失敗します。

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

ただし、中括弧とセミコロンを追加すると機能します。

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

これは、インデントが変更される可能性があるファイルから定義を貼り付ける場合にのみ問題になります。


少なくともバージョン7.6.3では、行が「=」で終わる行(次の行で定義が続く)がある場合は機能しません。
AdamC、2014年

1
letの2行目と3行目が十分にインデントされていないため、これはおそらく失敗します…?(さらに2つのスペース。)
Evi1M4chine 2016年

19

それは次のようになります:{:}、かなり新しい機能です。GHCをアップグレードする必要があるかもしれません。

編集:確認済み。http://www.haskell.org/ghc/docs/6.8.2/html/users_guide/release-6-8-2.htmlを参照


7

:{and だけでGHCをアップグレードしたくない場合は:}、すべてを1行で記述する必要があります。

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

Haskellの単一の定義が複数行で書かれる必要があることは知りません。上記は実際にGHCiで機能します:

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

doブロックなどの他の式では、中括弧とセミコロン(eugh)を使用した非レイアウト構文を使用する必要があります。


0

macOSカタリナ10.15.2でGHCiバージョン8.2.1を使用しています。以下は、関数型宣言とガードの両方を組み合わせる方法です。左側の縦棒はGHCiの複数行を示しています。

λ: let abs' :: (Num a, Ord a) => a -> a
 |     abs' n | n >= 0 = n | otherwise = -n
 | 
λ: abs' 7
7
λ: abs' (-7)
7

1
を使用:{し、型宣言の前:}に指定するlet 必要がない場合は、2行目以降をインデントする必要はありません。
davidA

davidAどうもありがとうございました。それはまさに私が探していたものですが、見つけることができませんでした。
ゴールデンサム

0

両方の行を一度に貼り付けるか、新しい行ごとにcontrol-enterを使用すると、少なくともhttps://repl.it/languages/haskellですべてがまとめられます。2行目の先頭に2つのドットが表示されます。または、ファイルに入れて、ファイルを:load(:l main)します。なぜabsは負の数では機能しないのですか?ああ、あなたは数を括弧で囲まなければなりません。

   let abs n | n >= 0 = n 
..           | otherwise = -n
   abs (-1)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.