คำสั่งหลายบรรทัดใน GHCi


139

ฉันมีปัญหาในการป้อนคำสั่งหลายบรรทัดใน ghci

โค้ด 2 บรรทัดต่อไปนี้ทำงานจากไฟล์:

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

แต่เมื่อฉันป้อน ghci ฉันได้รับข้อผิดพลาด:

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

ฉันลองใส่รหัสเข้าไปข้างใน:{ ... :}ด้วย แต่ก็ใช้ไม่ได้กับตัวอย่างนี้เช่นกันเพราะนี่เป็นเพียงการต่อท้ายบรรทัดให้เป็นบรรทัดเดียวซึ่งไม่ควรเป็นเช่นนั้น

ฉันใช้ WinGHCi เวอร์ชัน 2011.2.0.1


2
เป็นไปได้ที่จะซ้ำกันของวิธีกำหนดฟังก์ชันใน ghci ในหลายบรรทัด
devnull

คำตอบ:


189

โดยส่วนใหญ่คุณสามารถใช้การอนุมานประเภทเพื่อหาลายเซ็นให้คุณได้ ในตัวอย่างของคุณสิ่งต่อไปนี้เพียงพอแล้ว:

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

โปรดทราบว่าคุณสามารถบีบสิ่งนี้ลงในบรรทัดเดียว:

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

คุณสามารถดูข้อมูลเพิ่มเติมเกี่ยวกับการโต้ตอบกับ ghci ในการประเมินผลแบบโต้ตอบได้ที่ส่วนพร้อมต์ของเอกสาร


1
ขอบคุณมากสำหรับทั้งสองวิธีแก้ปัญหา แต่ฉันมีคำถามอื่นที่เกี่ยวข้อง: เหตุใดจึงต้องใช้ช่องว่างนำหน้าสี่ช่องในบรรทัดที่สอง (ก่อน addTwo) และสิ่งนี้จะต้องแน่นอนหากมีช่องว่างน้อยกว่าหรือมากกว่าแสดงว่ามีข้อผิดพลาด
R71

9
@ ร็อกletเริ่มบล็อก; รายการในบล็อกถูกจัดกลุ่มตามการเยื้อง และอักขระที่ไม่ใช่ช่องว่างตัวแรกในบล็อกจะตั้งค่าการเยื้องที่จะจัดกลุ่ม เนื่องจากอักขระที่ไม่ใช่ช่องว่างตัวแรกในletบล็อกด้านบนเป็นaของaddTwoบรรทัดทั้งหมดในบล็อกจะต้องเยื้องให้ลึกเท่าaกันทุกประการ
Daniel Wagner

ขอบคุณ. ฉันยังสังเกตเห็นว่าในบล็อกอื่น ๆ / ที่ไหน นี่เป็นความแตกต่างอย่างมากจากภาษาอื่น ๆ ที่ไม่สนใจช่องว่างดังนั้นฉันจึงมีปัญหาในการเข้าใจ
R71

130

แก้ปัญหานี้โดยเริ่ม GHCI แล้วพิมพ์:set +m:

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

บูม


เกิดอะไรขึ้นที่นี่ (และฉันกำลังพูดถึงคุณเป็นส่วนใหญ่คนที่ googling เพื่อขอความช่วยเหลือในขณะที่ดำเนินการผ่านLearn You A Haskell ) คือ GHCI เป็นสภาพแวดล้อมแบบโต้ตอบที่คุณเปลี่ยนการผูกชื่อฟังก์ชันได้ทันที คุณต้องรวมนิยามฟังก์ชันของคุณไว้ในletบล็อกเพื่อให้ Haskell รู้ว่าคุณกำลังจะกำหนดอะไรบางอย่าง :set +mสิ่งที่เป็นชวเลขสำหรับหลาย:{ รหัส :}สร้าง

letช่องว่างยังมีความสำคัญในบล็อกเพื่อให้คุณมีเพื่อเยื้องนิยามฟังก์ชันของคุณหลังจากที่การกำหนดประเภทของคุณโดยสี่ช่องว่างที่จะบัญชีสำหรับสี่ช่องว่างใน


5
เรียบง่าย แต่ไม่ชัดเจน ฉันอยากจะกรี๊ดกับหนังสือที่ฉันใช้ที่ไม่ได้บอกฉันว่าในหน้า 1!
ทิม

2
จากลินุกซ์เชลล์echo ':set +m' >> ~/.ghciเพื่อให้การตั้งค่านี้คงอยู่
eigenfield

คุณสามารถมีได้letด้วยตัวเองในบรรทัดแรกจากนั้นส่วนที่เหลือทั้งหมดไม่จำเป็นต้องเยื้องเลย โดยที่ช่องว่างมีค่าอย่างแท้จริงคือจะต้องไม่มีช่องว่างต่อท้ายบนเส้นของคุณ ช่องว่างต่อท้ายจะนับเป็น Enter พิเศษและแบ่งบล็อกหลายบรรทัด
Will Ness


5

ในฐานะของGHCI เวอร์ชัน 8.0.1 , letจะต้องไม่มีการกำหนดฟังก์ชั่นใน 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 +mหลายบรรทัด(ใช้เพื่อเปิดใช้งานการป้อนข้อมูลหลายบรรทัดใน GHCI):

λ: 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.0In the expression: addTwo 2.0 1.0
      In an equation for ‘it’: it = addTwo 2.0 1.0

2

ในการขยายคำตอบของ Aaron Hallในเวอร์ชัน 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) คุณไม่จำเป็นต้องใช้คำสั่งวงเล็บปีกกาตราบใดที่ไม่มีช่องว่างต่อท้ายบรรทัดรหัส
Will Ness

อืม:set +mคุณสามารถใช้letกับบรรทัดของมันเองได้หรือไม่? คุณทำได้ - เจ๋งมาก ขอบคุณ.
davidA

อืมฉันเจอบางกรณีที่แค่พิมพ์ขึ้นletบรรทัดใหม่ก็ใช้ไม่ได้ ดูการแก้ไขของฉัน
davidA
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.