เมื่อเร็ว ๆ นี้ฉันเริ่มเรียนรู้ Haskell เพราะฉันต้องการที่จะขยายความรู้ของฉันในการเขียนโปรแกรมฟังก์ชั่นและฉันต้องบอกว่าฉันรักมันจริงๆ ทรัพยากรที่ฉันใช้อยู่ในขณะนี้คือ 'Haskell Fundamentals Part 1' บน Pluralsight น่าเสียดายที่ฉันมีปัญหาในการทำความเข้าใจคำพูดหนึ่งของอาจารย์ผู้สอนเกี่ยวกับรหัสต่อไปนี้และหวังว่าพวกคุณจะเข้าใจในหัวข้อนี้
รหัสที่มาพร้อมกับ
helloWorld :: IO ()
helloWorld = putStrLn "Hello World"
main :: IO ()
main = do
helloWorld
helloWorld
helloWorld
อ้าง
หากคุณมีการกระทำ IO เดียวกันหลายครั้งใน do-block มันจะถูกเรียกใช้หลายครั้ง ดังนั้นโปรแกรมนี้พิมพ์สตริง 'Hello World' สามครั้ง ตัวอย่างนี้ช่วยอธิบายว่าputStrLnไม่ใช่ฟังก์ชันที่มีผลข้างเคียง เราเรียกใช้putStrLnฟังก์ชันหนึ่งครั้งเพื่อกำหนดhelloWorldตัวแปร หากputStrLnมีผลข้างเคียงของการพิมพ์สตริงมันจะพิมพ์เพียงครั้งเดียวและhelloWorldตัวแปรซ้ำใน do-block หลักจะไม่มีผลกระทบใด ๆ
ในภาษาโปรแกรมอื่น ๆ ส่วนใหญ่โปรแกรมเช่นนี้จะพิมพ์ 'Hello World' เพียงครั้งเดียวเนื่องจากการพิมพ์จะเกิดขึ้นเมื่อมีputStrLnการเรียกใช้ฟังก์ชัน ความแตกต่างที่ลึกซึ้งนี้มักจะทำให้ผู้เริ่มต้นคิดมากขึ้นและคิดว่าคุณเข้าใจไหมว่าทำไมโปรแกรมนี้พิมพ์ 'Hello World' สามครั้งและทำไมมันถึงพิมพ์ได้เพียงครั้งเดียวถ้าputStrLnฟังก์ชั่นการพิมพ์เป็นผลข้างเคียง
สิ่งที่ฉันไม่เข้าใจ
สำหรับฉันดูเหมือนเป็นเรื่องธรรมดาที่สตริง 'Hello World' จะถูกพิมพ์สามครั้ง ฉันรับรู้helloWorldตัวแปร (หรือฟังก์ชั่น?) เป็นประเภทการโทรกลับซึ่งถูกเรียกใช้ในภายหลัง สิ่งที่ฉันไม่เข้าใจคือถ้าputStrLnมีผลข้างเคียงมันจะส่งผลให้สายที่ถูกพิมพ์เพียงครั้งเดียว หรือทำไมมันจะพิมพ์เพียงครั้งเดียวในภาษาการเขียนโปรแกรมอื่น ๆ
สมมติว่าในรหัส C # ฉันจะสมมติว่ามันมีลักษณะเช่นนี้:
C # (ซอ)
using System;
public class Program
{
public static void HelloWorld()
{
Console.WriteLine("Hello World");
}
public static void Main()
{
HelloWorld();
HelloWorld();
HelloWorld();
}
}
ฉันแน่ใจว่าฉันกำลังมองหาบางสิ่งที่ค่อนข้างง่ายหรือตีความคำศัพท์ของเขาผิด ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมอย่างมาก.
แก้ไข:
ขอบคุณสำหรับคำตอบของคุณ! คำตอบของคุณช่วยให้ฉันเข้าใจแนวคิดเหล่านี้ได้ดีขึ้น ฉันคิดว่ามันยังไม่ได้คลิกเลย แต่ฉันจะกลับมาอ่านหัวข้อต่อไปในอนาคตขอบคุณ!
putStrLn ไม่มีผลข้างเคียง; มันแค่คืนค่าการกระทำของ IO การกระทำของIO แบบเดียวกันสำหรับการโต้แย้ง"Hello World"ไม่ว่าคุณจะโทรputStrLnไปกี่ครั้งก็ตาม
helloworldจะไม่เป็นการกระทำที่พิมพ์Hello worldออกมา ก็จะได้รับค่าส่งกลับโดยputStrLn หลังจากที่ มันพิมพ์Hello World(กล่าวคือ())
helloWorld = Console.WriteLine("Hello World");คุณไม่ทำเช่น คุณเพียงแค่มีConsole.WriteLine("Hello World");ในHelloWorldฟังก์ชั่นที่จะดำเนินการทุกครั้งที่HelloWorldมีการเรียก ตอนนี้คิดว่าเกี่ยวกับสิ่งที่ทำhelloWorld = putStrLn "Hello World" helloWorldจะได้รับมอบหมายให้ monad IO ()ซึ่งประกอบด้วย เมื่อคุณผูกมันแล้วมัน>>=ก็จะทำกิจกรรมของมัน (การพิมพ์บางอย่าง) และจะให้()ทางด้านขวาของผู้ประกอบการผูก
helloWorldคงที่เช่นเขตข้อมูลหรือตัวแปรใน C #helloWorldมีพารามิเตอร์ไม่มีที่จะถูกนำไปใช้เป็น