ทำไมการเข้าถึง System.Info ไม่ถือว่าเป็นการดำเนินการ IO ใน Haskell


25

ในโมดูลSystem.Infoฉันเห็นฟังก์ชั่นเหล่านี้:

os :: String
arch :: String
compilerName :: String
compilerVersion :: Version

ทำไมจึงไม่มีIOมี? พวกเขากำลังเข้าถึงระบบ ... ฉันผิดหรือเปล่า? ความคาดหวังของฉันเป็นสิ่งที่ชอบ:

os :: IO String
arch :: IO String
compilerName :: IO String
compilerVersion :: IO Version

ใช้กรณี:

      print os            -- "darwin"
      print arch          -- "x86_64"
      print compilerName  -- "ghc"

คำตอบ:


29

คุณไม่ได้รับข้อมูลนั้นขณะใช้งานจริง พวกเขาจะฮาร์ดโค้ดในคอมไพเลอร์ตามที่ติดตั้งบนระบบของคุณ

นี้เป็นที่ชัดเจนมากที่สุดถ้าคุณมองไปที่คำนิยามสำหรับcompilerNameที่พบในhttp://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html

compilerName :: String
compilerName = "ghc"

แต่ถึงอย่างนั้น os

os :: String
os = HOST_OS

ถูกกำหนดในแง่ของชื่อที่ไม่ได้กำหนดไว้เป็นอย่างอื่นHOST_OS(ค่าเริ่มต้นด้วยตัวอักษรตัวพิมพ์ใหญ่ ??) ซึ่งแสดงให้เห็นว่าเป็นเพียงตัวยึดตำแหน่งที่จะถูกแทนที่ในระหว่างการติดตั้ง

บางคนสามารถแก้ไขฉันได้ (โปรด!) แต่{-# LANGUAGE CPP #-}pragma ที่ด้านบนของไฟล์นั้นแสดงให้เห็นว่าHOST_OSและสิ่งที่คล้ายกันจะถูกแทนที่ด้วยสตริงที่เหมาะสมโดยตัวประมวลผลล่วงหน้า C ก่อนการรวบรวม


2
หาก OP ต้องการให้มีบางส่วนIOในนั้นมีเสื้อคลุมรอบ ๆuname(3)พร้อมใช้งานบนแฮ็กเกอร์: hackage.haskell.org/package/bindings-uname
thsutton

19

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

แต่นั่นคือเหตุผลแบบดั้งเดิมทั้งหมด Haskell เป็นภาษาเก่า (ไม่จริงๆมันเก่ากว่า Java เป็นเวลาหลายปี) ไลบรารีจำนวนมากถูกสร้างขึ้นด้วยเหตุผลที่ไม่ถือว่าเป็นแนวปฏิบัติที่ดีที่สุดอีกต่อไป นี่คือตัวอย่างของสิ่งนั้น ห้องสมุดสมัยใหม่ที่เปิดเผยพวกเขาอาจจะทำให้พวกเขาดำเนินการ IO แม้ว่าผลลัพธ์จะไม่เปลี่ยนแปลงหลังจากการรวบรวม การใช้ประโยชน์จากการวางสิ่งที่ไม่ใช่ค่าคงที่ในระดับซอร์สหลังการกระทำของ IO แม้ว่าจะมีข้อยกเว้นที่น่าสังเกตเช่นIntการเปลี่ยนขนาดระหว่างแพลตฟอร์ม 32 และ 64 บิต

ไม่ว่าในกรณีใด ๆ ... ฉันจะบอกว่าความคาดหวังของคุณแข็งแกร่งและประเภทเหล่านั้นเป็นผลมาจากเหตุการณ์ที่แปลกประหลาดทางประวัติศาสตร์


-9

แก้ไข: ขอบคุณ @interjay และ @Antal Spector-Zabusky สำหรับการอธิบายว่าทำไมคำตอบนี้จึงถูกลดระดับลง พวกเขาเขียน

เอกสารประกอบนั้นทำให้เข้าใจผิดเล็กน้อย ค่าจะถูก hardcoded ลงในคอมไพเลอร์ GHC หลังจาก 48 ปีคุณจะรู้ว่ารหัสจริงสำคัญกว่าเอกสารเสมอ - interjay เมื่อวานนี้ @ andy256 คุณถูกต้องจริง ๆ ว่าเอกสารนั้นไม่ดี (แน่นอนว่าเป็นส่วนหนึ่งของเหตุผลที่ฟรานซิสโกถามคำถามนี้ตั้งแต่แรก) และความสับสนของคุณเป็นที่เข้าใจ สิ่งที่เกี่ยวกับแฮสเค็ลล์คือถ้าค่าของสตริงเหล่านั้นอาจแตกต่างกันไปในขณะรันไทม์นั่นจะเป็นข้อผิดพลาดที่ร้ายแรง - ไม่อนุญาตให้เปลี่ยนตัวแปร นี่คือความสำคัญของคอนสตรัคเตอร์ประเภท IO - เพราะมันหมายถึงการคำนวณที่ได้รับอนุญาตให้เข้าถึง "โลกภายนอก" ดังนั้นสิ่งที่ผลลัพธ์สามารถเปลี่ยนแปลงได้ การเรียกใช้ระบบเป็นตัวอย่างที่ดีของการดำเนินการ IO … [1/2] - Antal Spector-Zabusky 9 ชั่วโมงที่ผ่านมา @ andy256 … (การกระทำของ IO อีกอย่างคือ "อัปเดตตัวนับทั่วโลก") ดังนั้นเมื่อเราเห็นสตริงเรารู้ว่ามันไม่สามารถทำการสื่อสารใด ๆ กับ ระบบปฏิบัติการภายใต้ประทุน นี่อาจเป็นเหตุผลที่น่าแปลกใจหากคุณไม่คุ้นเคยกับ Haskell มันไม่ง่ายเลยที่จะนำระบบปฏิบัติการ :: String ไปใช้ในการเรียกใช้ระบบ - ค่าดังกล่าวไม่สามารถใช้งานได้ใน Haskell พื้นฐานจะเป็นการละเมิดความคาดหวังของโปรแกรมเมอร์ทุกคน ทำงานและอาจรวมถึงการรวบรวมคอมไพเลอร์และออพติไมเซอร์ (ไม่ใช่ความกังวลในเชิงทฤษฎี - มีคำตอบสแต็คโอเวอร์โฟลว์ที่ผู้คนพบเจอกับปัญหาแบบอะนาล็อก) [2/2] - Antal Spector-Zabusky นี่อาจเป็นเหตุผลที่น่าแปลกใจหากคุณไม่คุ้นเคยกับ Haskell มันไม่ง่ายเลยที่จะนำระบบปฏิบัติการ :: String ไปใช้ในการเรียกใช้ระบบ - ค่าดังกล่าวไม่สามารถใช้งานได้ใน Haskell พื้นฐานจะเป็นการละเมิดความคาดหวังของโปรแกรมเมอร์ทุกคน ทำงานและอาจรวมถึงการรวบรวมคอมไพเลอร์และออพติไมเซอร์ (ไม่ใช่ความกังวลในเชิงทฤษฎี - มีคำตอบสแต็คโอเวอร์โฟลว์ที่ผู้คนพบเจอกับปัญหาแบบอะนาล็อก) [2/2] - Antal Spector-Zabusky นี่อาจเป็นเหตุผลที่น่าแปลกใจหากคุณไม่คุ้นเคยกับ Haskell มันไม่ง่ายเลยที่จะนำระบบปฏิบัติการ :: String ไปใช้ในการเรียกใช้ระบบ - ค่าดังกล่าวไม่สามารถใช้งานได้ใน Haskell พื้นฐานจะเป็นการละเมิดความคาดหวังของโปรแกรมเมอร์ทุกคน ทำงานและอาจรวมถึงการรวบรวมคอมไพเลอร์และออพติไมเซอร์ (ไม่ใช่ความกังวลในเชิงทฤษฎี - มีคำตอบสแต็คโอเวอร์โฟลว์ที่ผู้คนพบเจอกับปัญหาแบบอะนาล็อก) [2/2] - Antal Spector-Zabusky และอาจถึงขั้นเดินทางไปยังคอมไพเลอร์และออพติไมเซอร์ (ไม่ใช่ข้อกังวลทางทฤษฎี - มีคำตอบสแต็คโอเวอร์โฟลว์ที่ผู้คนพบเจอปัญหาแบบอะนาล็อก) [2/2] - Antal Spector-Zabusky และอาจถึงขนาดคอมไพเลอร์และออพติไมเซอร์ (ไม่ใช่ความกังวลในเชิงทฤษฎี - มีคำตอบสแต็คโอเวอร์โฟลว์ที่ผู้คนพบเจอกับปัญหาแบบอะนาล็อก) [2/2] - Antal Spector-Zabusky

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

คำตอบเดิม:

ฉันไม่ใช่โปรแกรมเมอร์ของ Haskell แต่คำตอบสองคำตอบที่ได้รับแล้วไม่ตรงกับเอกสารที่ OP เชื่อมโยง

การตีความเอกสารของฉันมีดังนี้

os :: String - สิ่งนี้จะให้ "ระบบปฏิบัติการที่โปรแกรมกำลังทำงานอยู่"

ฉันคาดหวังว่านี่จะเป็นการเรียกใช้ระบบเพื่อรับข้อมูล เนื่องจากระบบที่คอมไพล์โปรแกรมอาจแตกต่างจากระบบที่รันอยู่จึงไม่สามารถใส่ค่าโดยคอมไพเลอร์ หากรหัสถูกตีความแล้วล่ามสามารถให้ผลลัพธ์ซึ่งจะต้องได้รับผ่านการเรียกของระบบ

arch :: String - สิ่งนี้จะให้ "สถาปัตยกรรมเครื่องที่โปรแกรมกำลังทำงาน"

ฉันคาดหวังอีกครั้งว่านี่จะเป็นการเรียกใช้ระบบเพื่อรับข้อมูล เนื่องจากระบบที่คอมไพล์โปรแกรมอาจแตกต่างจากระบบที่รันอยู่จึงไม่สามารถใส่ค่าโดยคอมไพเลอร์

compilerName :: String - สิ่งนี้จะให้คุณ "การใช้งาน Haskell ซึ่งโปรแกรมรวบรวมหรือกำลังตีความ"

ค่านี้ถูกแทรกโดยตัวแปล / ตัวแปล

compilerVersion :: String- สิ่งนี้จะให้ "เวอร์ชันcompilerNameที่โปรแกรมรวบรวมหรือกำลังตีความ"

ค่านี้ถูกแทรกโดยตัวแปล / ตัวแปล

ในขณะที่คุณอาจพิจารณาการเรียกสองครั้งแรกเพื่อรับอินพุตผลลัพธ์มาจากค่าที่ระบบปฏิบัติการถือไว้ โดยทั่วไปแล้ว I / O หมายถึงการเข้าถึงที่เก็บข้อมูลรอง


3
มันไม่เป็นความจริงสำหรับฮาเซล ที่นี่การคำนวณใด ๆ จะไม่เรียงลำดับและผลลัพธ์ของมันจะถูกเก็บไว้ ฟังก์ชั่นนั้นบริสุทธิ์ดังนั้นถ้าฟังก์ชั่นไม่รับ args มากกว่ามันจะเหมือนกับค่าคงที่ ฟังก์ชั่นของ arg หนึ่งดูเหมือนว่าเพียง hashmaps หรือพจนานุกรมซึ่งคำนวณค่าตามคีย์ คุณไม่สามารถใช้สภาพแวดล้อมภายนอกทำ syscalls ในฟังก์ชั่นดังกล่าวคุณไม่สามารถรับหมายเลขสุ่มหรือวันที่ปัจจุบันได้ แต่ถ้าคุณต้องการใช้ "sequencing" หรือสภาพแวดล้อมจริง ๆ คุณต้องใช้IOmonad เพื่อจำลองสถานะเลียนแบบลำดับการทำงาน
Yuri Kovalenko

"คุณไม่สามารถใช้สภาพแวดล้อมภายนอกทำ syscalls ในฟังก์ชั่นดังกล่าว" - คุณสามารถทำได้โดยเฉพาะอย่างยิ่งถ้า "คุณ" เป็นคอมไพเลอร์ Haskell! มันจะง่ายมากสำหรับการนำ Haskell ไปใช้os :: Stringเพื่อที่จะทำการเรียกระบบเมื่อประเมินผล
แทนเนอร์สวิตต์

2
ฉันไม่คิดว่าคุณเข้าใจถึงความสำคัญของ IO monad ใน Haskell
Sneftel

@Sftftel แน่นอนคุณถูกต้อง ฉันเลือกที่จะตอบเพราะหลังจาก 48 ปีของการเขียนโปรแกรมในทุกกระบวนทัศน์และการเขียนคอมไพเลอร์แปลก ๆ คำตอบเริ่มต้นไม่ตรงกับเอกสารประกอบและพวกเขาก็ยังทำไม่ได้ มันชัดเจนว่าosและarchจะได้รับที่รันไทม์
andy256

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