Antarmuka bebas efek samping di atas perpustakaan stateful


16

Dalam sebuah wawancara dengan John Hughes di mana ia berbicara tentang Erlang dan Haskell, ia memiliki pendapat berikut tentang penggunaan perpustakaan negara di Erlang:

Jika saya ingin menggunakan perpustakaan stateful, saya biasanya membangun antarmuka bebas efek samping di atasnya sehingga saya dapat menggunakannya dengan aman di sisa kode saya.

Apa yang dia maksud dengan ini? Saya mencoba memikirkan contoh bagaimana ini akan terlihat, tetapi imajinasi dan / atau pengetahuan saya mengecewakan saya.


Nah, jika negara ada, itu tidak akan hilang. Caranya adalah dengan menciptakan sesuatu yang akan melacak ketergantungan. Jawaban Haskell standar adalah "monad" atau "panah" yang lebih maju . Mereka agak sulit untuk membungkus kepala Anda dan saya tidak pernah benar-benar melakukannya, jadi orang lain harus mencoba menjelaskannya.
Jan Hudec

Jawaban:


12

(Saya tidak tahu Erlang, dan saya tidak bisa menulis Haskell, tapi saya pikir saya bisa menjawab demikian)

Nah, dalam wawancara itu contoh perpustakaan generasi nomor acak diberikan. Berikut ini adalah kemungkinan antarmuka stateful:

# create a new RNG
var rng = RNG(seed)

# every time we call the next(ceil) method, we get a new random number
print rng.next(10)
print rng.next(10)
print rng.next(10)

Output mungkin 5 2 7. Bagi seseorang yang menyukai kekekalan, ini jelas salah! Seharusnya 5 5 5, karena kita memanggil metode pada objek yang sama.

Jadi apa yang akan menjadi antarmuka stateless? Kita dapat melihat urutan angka acak sebagai daftar malas yang dievaluasi, di mana nextsebenarnya mengambil kepala:

let rng = RNG(seed)
let n : rng = rng in
  print n
  let n : rng = rng in
    print n
    let n : rng in
      print n

Dengan antarmuka seperti itu, kami selalu dapat kembali ke keadaan sebelumnya. Jika dua potong kode Anda merujuk ke RNG yang sama, mereka sebenarnya akan mendapatkan urutan angka yang sama. Dalam pola pikir fungsional, ini sangat diinginkan.

Menerapkan ini dalam bahasa stateful tidak begitu rumit. Sebagai contoh:

import scala.util.Random
import scala.collection.immutable.LinearSeq

class StatelessRNG (private val statefulRNG: Random, bound: Int) extends LinearSeq[Int] {
  private lazy val next = (statefulRNG.nextInt(bound), new StatelessRNG(statefulRNG, bound))

  // the rest is just there to satisfy the LinearSeq trait
  override def head = next._1
  override def tail = next._2
  override def isEmpty = false
  override def apply(i: Int): Int = throw new UnsupportedOperationException()
  override def length = throw new UnsupportedOperationException()
}

// print out three nums
val rng = new StatelessRNG(new Random(), 10)
rng.take(3) foreach (n => println(n))

Setelah Anda menambahkan sedikit gula sintaksis sehingga rasanya seperti daftar, ini sebenarnya cukup bagus.


1
Adapun contoh pertama Anda: rnd.next (10) menghasilkan nilai-nilai yang berbeda setiap kali tidak ada hubungannya dengan kekekalan sebanyak yang harus dilakukan dengan definisi fungsi: fungsi harus 1-ke-1. (+1 sekalipun, barang bagus)
Steven Evers

Terima kasih! Itu adalah penjelasan dan contoh yang sangat bagus, mudah dipahami
beta

1

Konsep utama di sini adalah bahwa keadaan eksternal bisa berubah . Perpustakaan yang tidak memiliki keadaan eksternal yang dapat berubah, adalah perpustakaan yang bebas dari efek samping. Setiap fungsi di perpustakaan seperti itu hanya tergantung pada argumen yang diteruskan ke dalamnya.

  • Jika fungsi Anda mengakses sumber daya apa pun yang tidak dibuat olehnya, diberikan padanya (mis. Sebagai parameter), maka itu tergantung pada keadaan eksternal .
  • Jika fungsi Anda membuat sesuatu yang tidak diteruskan ke pemanggil (dan tidak menghancurkannya) maka fungsi Anda menciptakan keadaan eksternal.
  • Ketika keadaan eksternal dari atas dapat memiliki nilai yang berbeda pada waktu yang berbeda, maka itu bisa berubah .

Tes lakmus berguna yang saya gunakan:

  • jika fungsi A perlu dijalankan sebelum fungsi B maka A menciptakan keadaan eksternal yang menjadi tempat bergantungnya B.
  • jika suatu fungsi yang saya tulis tidak dapat di-memo, maka itu tergantung pada keadaan eksternal yang bisa berubah. (Memoisasi itu mungkin bukan ide yang baik karena tekanan memori, tetapi itu masih mungkin dilakukan)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.