Làm thế nào để xác định một hàm trong ghci trên nhiều dòng?


161

Tôi đang cố gắng xác định bất kỳ hàm đơn giản nào kéo dài nhiều dòng trong ghci, lấy ví dụ sau đây làm ví dụ:

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

Cho đến nay tôi đã thử nhấn Enter sau dòng đầu tiên:

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

Tôi cũng đã cố gắng sử dụng các lệnh :{:}nhưng tôi không đi được xa:

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

Tôi đang sử dụng GHC Interactive phiên bản 6.6 cho Haskell 98 trên Linux, tôi còn thiếu gì?


20
Vui lòng nâng cấp cài đặt GHC của bạn. GHC 6.6 đã gần 5 tuổi! Các phiên bản mới nhất của Haskell có tại đây: haskell.org/pl platform
Don Stewart

có thể trùng lặp các lệnh Nhiều dòng trong GHCi
mmmmmm

1
@Mark OP này đã thử các giải pháp cho vấn đề đó. Vấn đề này là do một ghci lỗi thời, không thiếu kiến ​​thức về những việc cần làm. Giải pháp tại đây: nâng cấp. Giải pháp đó: sử dụng :{, :}.
AndrewC

Câu trả lời:


124

Đối với lính canh (như ví dụ của bạn), bạn chỉ có thể đặt tất cả chúng trên một dòng và nó hoạt động (lính canh không quan tâm đến khoảng cách)

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

Nếu bạn muốn viết hàm của mình với nhiều định nghĩa mà mẫu khớp với các đối số, như thế này:

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

Sau đó, bạn sẽ sử dụng dấu ngoặc nhọn với dấu chấm phẩy phân tách các định nghĩa

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

258

GHCi hiện có chế độ đầu vào đa dòng, được bật với: set + m. Ví dụ,

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

39
Đặt chế độ đa dòng làm cho ghcihoạt động giống như trình thông dịch Python trong vấn đề này. Rât thuận tiện! Thực tế bạn có thể tạo một .ghcitệp trong thư mục chính của bạn trong đó bạn đặt :set +mvà chế độ đa dòng sẽ trở thành mặc định mỗi khi bạn bắt đầu ghci!
kqr

2
Điều này thực sự tuyệt vời. Nhưng tôi đã nhận thấy rằng khi tôi đặt lời nhắc của mình bằng cách sử dụng :set prompt "λ "các dòng tiếp tục nói Preludethay vì λ. Còn đường nào để vòng lại chỗ đó không?
abhillman

2
Xem ở đây để biết bản vá để xác định lời nhắc tiếp tục mới ghc.haskell.org/trac/ghc/ticket/7509#no1
karakfa

4
Để ngăn Prelude xuất hiện trên các dòng tiếp tục, hãy thêm: set prompt2 "|" trong .ghci của bạn.
Nick

12
Bạn hoàn toàn có thể tránh thụt đầu dòng bằng cách sử dụng dấu let. Chỉ cần gõ a lettheo sau bởi một dòng mới let:. Rồi fac 0 = 1. Sau đó, fac n = n * fac (n-1)⏎ và bạn đã hoàn tất!
Iceland_jack

62

Dan là đúng, nhưng :{:}từng phải xuất hiện trên một dòng riêng của họ:

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

Điều này cũng tương tác với quy tắc bố cục, vì vậy khi sử dụng ký hiệu, có thể dễ dàng sử dụng dấu ngoặc và dấu hai chấm một cách rõ ràng. Ví dụ: định nghĩa này không thành công:

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

Nhưng nó hoạt động khi niềng răng và dấu chấm phẩy được thêm vào:

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

Điều này sẽ chỉ thực sự quan trọng khi dán định nghĩa từ một tệp, nơi thụt lề có thể thay đổi.


Điều này không hoạt động nếu bạn có một dòng kết thúc bằng '=' (với định nghĩa theo sau trên dòng tiếp theo), ít nhất là trong phiên bản 7.6.3.
AdamC

1
Có lẽ điều này thất bại, bởi vì dòng thứ hai và thứ ba của cho phép không được thụt lề đủ? (Hai không gian nữa.)
Evi1M4chine


7

Nếu bạn không muốn nâng cấp GHC chỉ cho :{:}, bạn sẽ cần phải viết tất cả trên một dòng:

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

Tôi không biết bất kỳ định nghĩa duy nhất nào trong Haskell phải được viết trên nhiều dòng. Trên đây thực sự hoạt động trong GHCi:

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

Đối với các biểu thức khác, chẳng hạn như docác khối, bạn sẽ cần sử dụng cú pháp không bố cục với dấu ngoặc nhọn và dấu chấm phẩy (eugh).


0

Tôi đang sử dụng GHCi, phiên bản 8.2.1 trên macOS Catalina 10.15.2. Sau đây là cách tôi đặt cả khai báo kiểu hàm và bộ bảo vệ với nhau. Lưu ý các thanh dọc bên trái là dành cho nhiều dòng GHCi.

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

1
Nếu bạn sử dụng :{:}bạn không cần chỉ định let trước khai báo kiểu của mình, nghĩa là bạn không cần thụt dòng thứ hai và dòng tiếp theo.
davidA

Cảm ơn bạn rất nhiều davidA. Đó chính xác là những gì tôi đã tìm kiếm nhưng không tìm thấy.
Ngón tay cái vàng

0

Có vẻ như dán cả hai dòng cùng một lúc hoặc sử dụng control-enter cho mỗi dòng mới giữ cho tất cả các dòng cùng nhau, ít nhất là tại https://repl.it/lacular/haskell . Bạn sẽ thấy 2 dấu chấm ở đầu dòng thứ hai. Hoặc đặt nó vào một tệp và: tải tệp (: l chính). Làm thế nào abs không hoạt động với số âm? Oh bạn phải đặt dấu ngoặc đơn xung quanh số.

   let abs n | n >= 0 = n 
..           | otherwise = -n
   abs (-1)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.