วิธีการกำหนดฟังก์ชั่นใน 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 `|'

ฉันพยายามใช้:{และ:}คำสั่งด้วย แต่ฉันก็ไม่ได้ไปไกล:

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

ฉันใช้ GHC Interactive เวอร์ชัน 6.6 สำหรับ Haskell 98 บน Linux ฉันจะพลาดอะไรไป?


20
โปรดอัปเกรดการติดตั้ง GHC ของคุณ GHC 6.6 เกือบ 5 ปีแล้ว! Haskell รุ่นล่าสุดอยู่ที่นี่: haskell.org/platform
Don Stewart

เป็นไปได้ที่ซ้ำกันของคำสั่งหลายบรรทัดใน GHCi
mmmmmm

1
@ ทำเครื่องหมาย OP นี้แล้วลองแก้ไขปัญหาที่เกิดขึ้น ปัญหานี้เกิดจาก ghci ที่ล้าสมัยไม่ขาดความรู้ในสิ่งที่ต้องทำ วิธีแก้ไขที่นี่: อัพเกรด โซลูชันที่นั่น: ใช้:{, :}.
AndrewC

คำตอบ:


124

สำหรับยาม (เช่นตัวอย่างของคุณ) คุณสามารถใส่พวกมันทั้งหมดในบรรทัดเดียวและมันใช้งานได้ (ยามไม่สนใจเรื่องระยะห่าง)

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

2
มันยอดเยี่ยมจริงๆ แต่ผมสังเกตว่าเมื่อผมตั้งของฉันพรอมต์โดยใช้:set prompt "λ "สายยังคงพูดแทนPrelude λมีวิธีใดบ้างที่จะหลีกเลี่ยงปัญหานี้
abhillman

2
ดูที่นี่สำหรับแพตช์เพื่อกำหนดพรอมต์ความต่อเนื่องใหม่ghc.haskell.org/trac/ghc/ticket/7509#no1
karakfa

4
หากต้องการป้องกันไม่ให้โหมโรงปรากฏในบรรทัดต่อเนื่องให้เพิ่ม: set prompt2 "|" ใน. gci ของคุณ
Nick

12
คุณสามารถสมบูรณ์letหลีกเลี่ยงการเยื้องใช้ต่อท้าย เพียงพิมพ์letตามด้วยบรรทัดใหม่: let⏎ จากนั้นfac 0 = 1⏎ จากนั้นfac n = n * fac (n-1)⏎⏎และคุณทำเสร็จแล้ว!
Iceland_jack

62

แดนถูกต้อง แต่:{และ:}แต่ละคนจะต้องปรากฏบนบรรทัดของตัวเอง:

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

สิ่งนี้ยังโต้ตอบกับกฎโครงร่างดังนั้นเมื่อใช้การทำเครื่องหมายอาจเป็นการง่ายกว่าที่จะใช้เครื่องมือจัดฟันและเซมิโคลอนแบบโคลอนอย่างชัดเจน ตัวอย่างเช่นนิยามนี้ล้มเหลว:

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

1
บางทีนี่อาจจะล้มเหลวเพราะบรรทัดที่สองและสามของการปล่อยให้เยื้องไม่เพียงพอ ... ? (ช่องว่างอีกสองช่อง)
Evi1M4chine


7

หากคุณไม่ต้องการอัปเกรด GHC เพียงเพื่อ:{และ:}คุณจะต้องเขียนทั้งหมดในบรรทัดเดียว:

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

ฉันไม่ทราบคำจำกัดความใด ๆ ใน Haskell ที่ต้องเขียนหลายบรรทัด การทำงานข้างต้นทำงานใน GHCi:

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

สำหรับนิพจน์อื่น ๆ เช่นdoบล็อกคุณจะต้องใช้ไวยากรณ์ที่ไม่ใช่เลย์เอาต์ด้วยเครื่องหมายปีกกาและเครื่องหมายอัฒภาค (eugh)


0

ฉันใช้ GHCi เวอร์ชัน 8.2.1 บน macOS Catalina 10.15.2 ต่อไปนี้เป็นวิธีที่ฉันใส่ทั้งการประกาศประเภทฟังก์ชั่นและกัน หมายเหตุแถบแนวตั้งทางด้านซ้ายมีไว้สำหรับ GHCi หลายบรรทัด

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

1
หากคุณใช้:{และ:}คุณไม่จำเป็นต้องระบุlet ก่อนการประกาศประเภทของคุณหมายความว่าคุณไม่จำเป็นต้องเยื้องบรรทัดที่สองและบรรทัดถัดไป
davidA

ขอบคุณมากดาวิ นั่นคือสิ่งที่ฉันกำลังมองหา แต่ไม่สามารถหาได้
Golden Thumb

0

ดูเหมือนว่าการวางสายทั้งสองครั้งหรือใช้ควบคุมการป้อนสำหรับสายใหม่ในแต่ละช่วยให้มันรวมกันทั้งหมดอย่างน้อยในhttps://repl.it/languages/haskell คุณจะเห็นจุด 2 จุดในตอนต้นของบรรทัดที่สอง หรือวางไว้ในไฟล์และ: โหลดไฟล์ (: l main) ทำไมเอบีเอสจึงไม่ทำงานกับจำนวนลบ? โอ้คุณต้องใส่วงเล็บล้อมรอบตัวเลข

   let abs n | n >= 0 = n 
..           | otherwise = -n
   abs (-1)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.