Bagaimana cara mendefinisikan fungsi dalam ghci melintasi beberapa baris?

161

Saya mencoba mendefinisikan fungsi sederhana apa pun yang membentang beberapa baris dalam ghci, ambil yang berikut sebagai contoh:

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

Sejauh ini saya sudah mencoba menekan Enter setelah baris pertama:

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

Saya juga telah mencoba untuk menggunakan :{dan :}perintah tetapi saya tidak sampai jauh:

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

Saya menggunakan GHC Interactive versi 6.6 untuk Haskell 98 di Linux, apa yang saya lewatkan?

Peter McG
sumber
20
Harap tingkatkan instalasi GHC Anda. GHC 6.6 hampir berumur 5 tahun! Versi terbaru Haskell ada di sini: haskell.org/platform
Don Stewart
kemungkinan duplikat dari perintah Multi-line di GHCi
mmmmmm
1
@ Mark OP ini sudah mencoba solusi untuk masalah itu. Masalah ini disebabkan oleh ghci yang ketinggalan zaman, bukan kurangnya pengetahuan tentang apa yang harus dilakukan. Solusi di sini: tingkatkan. Solusi ada: penggunaan :{, :}.
AndrewC

Jawaban:

124

Untuk penjaga (seperti contoh Anda), Anda bisa meletakkan semuanya di satu baris dan berfungsi (penjaga tidak peduli dengan jarak)

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

Jika Anda ingin menulis fungsi Anda dengan beberapa definisi yang cocok dengan pola pada argumen, seperti ini:

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

Kemudian Anda akan menggunakan kawat gigi dengan tanda koma yang memisahkan definisi

let { fact 0 = 1 ; fact n = n * fact (n-1) }
berita baru
sumber
258

GHCi sekarang memiliki mode input multiline, diaktifkan dengan: set + m. Sebagai contoh,

Prelude> :set +m
Prelude> let fac 0 = 1
Prelude|     fac n = n * fac (n-1)
Prelude|
Prelude> fac 10
3628800
karakfa
sumber
39
Pengaturan mode multiline membuat ghciberperilaku seperti interpreter Python dalam hal ini. Sangat mudah! Anda sebenarnya bisa membuat .ghcifile di direktori home Anda di mana Anda meletakkan :set +mdan mode multiline akan menjadi default setiap kali Anda memulai ghci!
kqr
2
Ini sangat mengagumkan. Tetapi saya perhatikan bahwa ketika saya mengatur prompt saya menggunakan :set prompt "λ "garis yang terus-menerus mengatakan Preludebukan λ. Ada cara untuk menyiasatinya?
abhillman
2
Lihat di sini untuk tambalan untuk menentukan prompt kelanjutan baru ghc.haskell.org/trac/ghc/ticket/7509#no1
karakfa
4
Untuk mencegah Prelude muncul di baris lanjutan, tambahkan juga: set prompt2 "|" di .ghci Anda.
Nick
12
Anda benar - benar dapat menghindari lekukan menggunakan jejak let. Cukup ketik a letdiikuti oleh baris baru: let⏎. Lalu fac 0 = 1⏎. Lalu fac n = n * fac (n-1)⏎ ⏎ dan kamu selesai!
Iceland_jack
62

Dan benar, tetapi :{dan :}masing-masing harus muncul di baris mereka sendiri:

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

Ini juga berinteraksi dengan aturan tata letak, jadi ketika menggunakan notasi mungkin lebih mudah untuk menggunakan kawat gigi dan semi-titik dua secara eksplisit. Misalnya, definisi ini gagal:

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

Tapi itu berfungsi ketika kawat gigi dan semi-titik dua ditambahkan:

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

Ini hanya akan sangat berarti ketika menempelkan definisi dari file, di mana indentasi dapat berubah.

Justin Bailey
sumber
Ini tidak berfungsi jika Anda memiliki garis yang diakhiri dengan '=' (dengan definisi berikut pada baris berikutnya), setidaknya dalam versi 7.6.3.
AdamC
1
Mungkin ini gagal, karena baris kedua dan ketiga dari hak tersebut tidak cukup berlekuk ...? (Dua spasi lagi.)
Evi1M4chine
7

Jika Anda tidak ingin meningkatkan GHC hanya untuk :{dan :}, Anda harus menulis semuanya dalam satu baris:

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

Saya tidak mengetahui adanya definisi tunggal dalam Haskell yang harus ditulis pada banyak baris. Hal di atas memang bekerja di GHCi:

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

Untuk ekspresi lain, seperti doblok, Anda harus menggunakan sintaks non-tata letak dengan kurung kurawal dan titik koma (eugh).

CA McCann
sumber
0

Saya menggunakan GHCi, versi 8.2.1 di macOS Catalina 10.15.2. Berikut ini adalah bagaimana saya menempatkan kedua deklarasi tipe fungsi dan penjaga. Perhatikan bilah vertikal di sebelah kiri adalah untuk beberapa baris GHCi.

λ: let abs' :: (Num a, Ord a) => a -> a
 |     abs' n | n >= 0 = n | otherwise = -n
 | 
λ: abs' 7
7
λ: abs' (-7)
7
Thumb Emas
sumber
1
Jika Anda menggunakan :{dan :}Anda tidak perlu menentukan let sebelum deklarasi tipe Anda, artinya Anda tidak perlu membuat indentasi baris kedua dan selanjutnya.
davidA
Terima kasih banyak davidA. Itulah tepatnya yang saya cari tetapi gagal menemukannya.
Golden Thumb
0

Sepertinya menyisipkan kedua baris sekaligus atau menggunakan control-enter untuk setiap baris baru menyimpan semuanya, setidaknya di https://repl.it/languages/haskell . Anda akan melihat 2 titik di awal baris kedua. Atau letakkan di file dan: muat file (: l main). Kenapa perut tidak bekerja dengan angka negatif? Oh, Anda harus meletakkan tanda kurung di sekitar nomor itu.

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