Haskells Weak Head ฟอร์มปกติ


9

ฉันสะดุดสิ่งที่น่ารำคาญบางอย่าง ฉันรู้ว่า Haskell ทำงานได้กับรูปแบบปกติของผู้อ่อนแอ (WHNF) และฉันรู้ว่านี่คืออะไร พิมพ์รหัสต่อไปนี้เป็น ghci (ฉันใช้คำสั่ง: sprint ซึ่งลดการแสดงออกของ WHNF ให้เป็นความรู้ของฉัน):

let intlist = [[1,2],[2,3]]
:sprint intlist

ให้intlist = _ความรู้สึกแบบนี้กับฉันโดยสิ้นเชิง

let stringlist = ["hi","there"]
:sprint stringlist 

ให้stringlist = [_,_] สิ่งนี้ทำให้ฉันสับสนแล้ว แต่แล้ว:

let charlist = [['h','i'], ['t','h','e','r','e']]
:sprint charlist

ให้อย่างแปลกใจ charlist = ["hi","there"]

เท่าที่ผมเข้าใจ Haskell สตริงมีอะไรอย่างอื่นมากกว่ารายชื่อของตัวอักษรซึ่งดูเหมือนว่าจะได้รับการยืนยันโดยการตรวจสอบชนิดและ"hi" :: [Char]['h','i'] :: [Char]

ฉันสับสนเพราะในการทำความเข้าใจของฉันทั้งสามตัวอย่างข้างต้นเป็นแบบเดียวกัน (รายการของรายการ) มากขึ้นและน้อยลงดังนั้นจึงควรลด WHNF เดียวกันนั่นคือ _ ฉันกำลังคิดถึงอะไร

ขอบคุณ


นี้ดูเหมือนว่าจะเกี่ยวข้อง
Bergi

@Bergi คำถามเหล่านั้นมีความเกี่ยวข้องอย่างแน่นอน แต่ดูเหมือนจะไม่ตอบว่าทำไม"bla"และ['b','l','a']จะออกมาแตกต่างกัน
leftaroundabout

@leftaroundabout เพราะ"bla"อาจจะมากเกินไป แต่['b','l','a']เป็นที่รู้จักกันเป็นString/ [Char]?
Bergi

1
@Bergi ฉันก็คิดเช่นกัน แต่ก็ไม่น่าเชื่อถือจริง ๆ เพราะ['b', 'l', 'a']อาจมีการใช้งานมากเกินไปและในทำนองเดียวกัน"bla"จะทำงานมากเกินไปหาก-XOverloadedStringsเปิดใช้งานอยู่
leftaroundabout

2
ดูเหมือน parser ที่เกี่ยวข้องอาจเฉพาะกับ GHCi? (ฉันไม่รู้ว่าคุณทดสอบ WHNF อย่างไรในโค้ดที่คอมไพล์ด้วย GHC) คำพูดนั้นดูเหมือนจะเป็นตัวกระตุ้น
chepner

คำตอบ:


5

โปรดทราบว่า:sprintจะไม่ลดนิพจน์เป็น WHNF ถ้าเป็นเช่นนั้นแล้วสิ่งต่อไปนี้จะให้4มากกว่า_:

Prelude> let four = 2 + 2 :: Int
Prelude> :sprint four
four = _

แต่:sprintใช้ชื่อของการผูกไว้ลัดเลาะการเป็นตัวแทนภายในของมูลค่าของการผูกและแสดงให้เห็นถึง "ส่วนที่ได้รับการประเมิน" แล้ว (เช่นชิ้นส่วนที่เป็นผู้สร้าง) ในขณะที่ใช้_เป็นตัวยึดสำหรับ thunks ประเมินค่า (เช่นฟังก์ชั่นขี้เกียจ โทร) หากค่าไม่ได้รับการประเมินอย่างสมบูรณ์จะไม่มีการประเมินผลใด ๆ แม้แต่ WHNF (และหากประเมินค่าอย่างสมบูรณ์คุณจะได้รับไม่ใช่แค่ WHNF)

สิ่งที่คุณสังเกตในการทดลองของคุณคือการรวมกันของ polymorphic เทียบกับประเภทตัวเลข monomorphic, การเป็นตัวแทนภายในที่แตกต่างกันสำหรับตัวอักษรสตริงและรายชื่อตัวละครที่ชัดเจน ฯลฯ โดยทั่วไปคุณสังเกตความแตกต่างทางเทคนิคในการรวบรวม ดังนั้นการตีความรายละเอียดการติดตั้งเหล่านี้ว่ามีส่วนเกี่ยวข้องกับ WHNF จะทำให้คุณสับสนอย่างสิ้นหวัง โดยทั่วไปคุณควรใช้:sprintเป็นเครื่องมือดีบั๊กเท่านั้นไม่ใช่วิธีเรียนรู้เกี่ยวกับ WHNF และความหมายของการประเมิน Haskell

หากคุณต้องการเข้าใจสิ่งที่:sprintกำลังทำจริง ๆ คุณสามารถเปิดการตั้งค่าสถานะบางอย่างใน GHCi เพื่อดูว่ามีการจัดการกับนิพจน์อย่างไรและในที่สุดก็รวบรวมเป็น bytecode:

> :set -ddump-simpl -dsuppress-all -dsuppress-uniques

หลังจากนี้เราจะเห็นเหตุผลที่คุณintlistให้_:

> let intlist = [[1,2],[2,3]]
==================== Simplified expression ====================
returnIO
  (: ((\ @ a $dNum ->
         : (: (fromInteger $dNum 1) (: (fromInteger $dNum 2) []))
           (: (: (fromInteger $dNum 2) (: (fromInteger $dNum 3) [])) []))
      `cast` <Co:10>)
     [])

คุณสามารถเพิกเฉยต่อreturnIOและ:โทรออกและมุ่งเน้นส่วนที่เริ่มต้นด้วย((\ @ a $dNum -> ...

นี่$dNumคือพจนานุกรมสำหรับNumข้อ จำกัด ซึ่งหมายความว่ารหัสที่สร้างขึ้นยังไม่ได้รับการแก้ไขประเภทที่แท้จริงaในประเภทNum a => [[a]]ดังนั้นการแสดงออกทั้งหมดยังคงแสดงว่าเป็นการเรียกใช้ฟังก์ชั่น (พจนานุกรมสำหรับ) Numประเภทที่เหมาะสม กล่าวอีกนัยหนึ่งมันเป็นสิ่งที่ไม่ได้ประเมินค่าและเราจะได้รับ:

> :sprint intlist
_

ในอีกทางหนึ่งระบุประเภทเป็นIntและรหัสแตกต่างอย่างสิ้นเชิง:

> let intlist = [[1::Int,2],[2,3]]
==================== Simplified expression ====================
returnIO
  (: ((: (: (I# 1#) (: (I# 2#) []))
         (: (: (I# 2#) (: (I# 3#) [])) []))
      `cast` <Co:6>)
     [])

และ:sprintผลลัพธ์ก็คือ:

> :sprint intlist
intlist = [[1,2],[2,3]]

ในทำนองเดียวกันสตริงตัวอักษรและรายการตัวอักษรที่ชัดเจนมีการแสดงที่แตกต่างกันอย่างสมบูรณ์:

> let stringlist = ["hi", "there"]
==================== Simplified expression ====================
returnIO
  (: ((: (unpackCString# "hi"#) (: (unpackCString# "there"#) []))
      `cast` <Co:6>)
     [])

> let charlist = [['h','i'], ['t','h','e','r','e']]
==================== Simplified expression ====================
returnIO
  (: ((: (: (C# 'h'#) (: (C# 'i'#) []))
         (: (: (C# 't'#)
               (: (C# 'h'#) (: (C# 'e'#) (: (C# 'r'#) (: (C# 'e'#) [])))))
            []))
      `cast` <Co:6>)
     [])

และความแตกต่างในการ:sprintส่งออกหมายถึงสิ่งประดิษฐ์ซึ่งเป็นส่วนหนึ่งของการแสดงออก GHCi พิจารณาประเมินผล (อย่างชัดเจน:ก่อสร้าง) เมื่อเทียบกับ unevaluated (คนunpackCString#thunks)

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