Baru-baru ini, saya mulai belajar Haskell karena saya ingin memperluas pengetahuan saya tentang pemrograman fungsional dan saya harus mengatakan saya sangat menyukainya sejauh ini. Sumber daya yang saya gunakan saat ini adalah kursus 'Haskell Fundamentals Part 1' di Pluralsight. Sayangnya saya mengalami kesulitan memahami satu kutipan khusus dari dosen tentang kode berikut dan berharap kalian bisa menjelaskan topik ini.
Kode Pengiring
helloWorld :: IO ()
helloWorld = putStrLn "Hello World"
main :: IO ()
main = do
helloWorld
helloWorld
helloWorld
Kutipan
Jika Anda memiliki tindakan IO yang sama beberapa kali dalam do-block, itu akan dijalankan beberapa kali. Jadi program ini mencetak string 'Hello World' tiga kali. Contoh ini membantu menggambarkan bahwa putStrLn
itu bukan fungsi dengan efek samping. Kami memanggil putStrLn
fungsi satu kali untuk mendefinisikan helloWorld
variabel. Jika putStrLn
ada efek samping dari mencetak string, itu hanya akan mencetak sekali dan helloWorld
variabel yang diulang dalam do-block utama tidak akan memiliki efek apa pun.
Di sebagian besar bahasa pemrograman lain, program seperti ini hanya akan mencetak 'Hello World' sekali saja, karena pencetakan akan terjadi ketika putStrLn
fungsinya dipanggil. Perbedaan yang halus ini sering membuat pemula tersandung, jadi pikirkanlah ini sedikit, dan pastikan Anda memahami mengapa program ini mencetak 'Hello World' tiga kali dan mengapa ia akan mencetaknya hanya sekali jika putStrLn
fungsi melakukan pencetakan sebagai efek samping.
Apa yang tidak saya mengerti
Bagi saya tampaknya hampir alami bahwa string 'Hello World' dicetak tiga kali. Saya menganggap helloWorld
variabel (atau fungsi?) Sebagai semacam panggilan balik yang dipanggil nanti. Yang tidak saya mengerti adalah, bagaimana jika putStrLn
memiliki efek samping, itu akan menghasilkan string yang dicetak hanya sekali. Atau mengapa hanya dicetak sekali dalam bahasa pemrograman lain.
Katakanlah dalam kode C #, saya akan menganggapnya akan terlihat seperti ini:
C # (Fiddle)
using System;
public class Program
{
public static void HelloWorld()
{
Console.WriteLine("Hello World");
}
public static void Main()
{
HelloWorld();
HelloWorld();
HelloWorld();
}
}
Saya yakin saya mengabaikan sesuatu yang cukup sederhana atau salah menafsirkan terminologinya. Bantuan apa pun akan sangat dihargai.
EDIT:
Terima kasih atas jawaban Anda! Jawaban Anda membantu saya mendapatkan pemahaman yang lebih baik tentang konsep-konsep ini. Saya pikir belum sepenuhnya diklik, tapi saya akan kembali ke topik di masa depan, terima kasih!
putStrLn
tidak memiliki efek samping; itu hanya mengembalikan tindakan IO, tindakan IO yang sama untuk argumen "Hello World"
tidak peduli berapa kali Anda menelepon putStrLn
.
helloworld
tidak akan menjadi tindakan yang mencetak Hello world
; itu akan menjadi nilai yang dikembalikan oleh putStrLn
setelah itu dicetak Hello World
(yaitu, ()
).
helloWorld = Console.WriteLine("Hello World");
. Anda hanya mengandung Console.WriteLine("Hello World");
dalam HelloWorld
fungsi yang akan dijalankan setiap kali HelloWorld
dipanggil. Sekarang pikirkan tentang apa yang helloWorld = putStrLn "Hello World"
membuatnya helloWorld
. Itu akan ditugaskan ke monad IO yang berisi ()
. Setelah Anda mengikatnya >>=
hanya akan melakukan aktivitasnya (mencetak sesuatu) dan akan memberikan Anda ()
di sisi kanan operator bind.
helloWorld
menjadi konstan seperti bidang atau variabel dalam C #. Tidak ada parameter yang diterapkanhelloWorld
.