Apakah Penggunaan Jenis Data Aljabar?

16

Saya membaca tentang Tipe Data Aljabar (terima kasih kepada Richard Minerich, saya menemukan penjelasan konsep yang sangat bagus). Meskipun saya pikir saya memahami gagasan tentang jenis penjumlahan dan jenis produk, dll., Yang saya tidak terlalu pahami adalah bagaimana Tipe Data Aljabar berguna di luar menentukan pencocokan pola. Apa hal lain yang bisa dilakukan seseorang dengan pencocokan pola ADT?


EDIT: Saya tidak bertanya apa yang bisa dilakukan pengembang dengan ADT yang tidak bisa dilakukan dengan objek. Saya bertanya apakah ada operasi lain yang diizinkan ADT; misalnya, dapatkah seseorang melakukan penalaran tambahan tentang jenis-jenis yang terlibat jika ADT digunakan? Apakah ADT memfasilitasi semacam analisis tipe yang tidak akan mungkin tanpa mereka?

Onorio Catenacci
sumber
2
Apa yang dapat Anda lakukan dengan objek kecuali metode memanggil?
1
ADT sebenarnya mengacu pada "tipe data abstrak", bukan tipe data aljabar .
Rein Henrichs
4
@Rein: Ini bisa merujuk pada tergantung pada konteksnya.
sepp2k
4
@Rein: Memang benar (yang menurut saya cukup mengejutkan untuk jujur): Namun artikel wikipedia untuk ADT mencantumkan Tipe Data Abstrak dan Tipe Data Aljabar sebagai arti yang mungkin. Dan ADT sangat umum digunakan sebagai singkatan untuk tipe data aljabar pada misalnya milis Haskell dan saluran IRC.
sepp2k
1
@Rein, saya tahu - hanya bosan mengetik "Tipe Data Aljabar" berulang-ulang dan saya pikir orang akan dapat memahami apa yang saya maksudkan dengan konteksnya.
Onorio Catenacci

Jawaban:

10

Tipe Data Aljabar berbeda karena dapat dibangun dari beberapa jenis "hal". Sebagai contoh, sebuah Pohon dapat mengandung apa pun (Kosong), Leaf, atau Node.

data Tree = Empty
          | Leaf Int
          | Node Tree Tree

Karena Node terdiri dari dua Pohon, tipe data aljabar dapat bersifat rekursif.

Pencocokan pola memungkinkan tipe data aljabar didekonstruksi dengan cara yang menjaga keamanan tipe. Pertimbangkan implementasi kedalaman berikut ini dan yang setara dengan kodesemu:

depth :: Tree -> Int
depth Empty = 0
depth (Leaf n) = 1
depth (Node l r) = 1 + max (depth l) (depth r)

dibandingkan dengan:

switch on (data.constructor)
  case Empty:
    return 0
  case Leaf:
    return 1
  case Node:
    let l = data.field1
    let r = data.field2
    return 1 + max (depth l) (depth r)

Ini memiliki kelemahan yang harus diingat oleh programmer untuk menggunakan Empty before Leaf sehingga field1 tidak diakses pada pohon Empty. Demikian juga, kasus Leaf harus dideklarasikan sebelum kasus Node sehingga field2 tidak diakses di Leaf. Dengan demikian jenis keamanan tidak dipertahankan oleh bahasa tetapi lebih memaksakan beban kognitif tambahan pada programmer. Ngomong-ngomong, saya mengambil contoh-contoh ini langsung dari halaman wikipedia.

Tentu saja, langauge yang mengetik bebek bisa melakukan sesuatu seperti ini:

class Empty
  def depth
    0
  end
end

class Leaf
  def depth
    1
  end
end

class Node
  attr_accessor :field1, :field2

  def depth
    1 + [field1.depth, field2.depth].max
  end
end

Jadi tipe data aljabar mungkin tidak benar-benar lebih baik daripada yang setara dengan OOP mereka, tetapi mereka memberikan serangkaian ketegangan yang berbeda untuk bekerja dengan ketika membangun perangkat lunak.

Rein Henrichs
sumber
9

Saya tidak begitu yakin penjelasan adalah semua yang sangat baik.

Tipe Data aljabar digunakan untuk membuat struktur data, seperti daftar dan pohon.

Misalnya pohon parse mudah diwakili dengan struktur data aljabar.

data BinOperator = Add
                 | Subtr
                 | Div
                 | Mult
                 | Mod
                 | Eq
                 | NotEq
                 | GreaterThan
                 | LogicAnd
                 | LogicOr
                 | BitAnd
                 | BitOr
                 | ...

data UnOperator = Negate
                | Not
                | Increment
                | Decrement
                | Complement
                | Ref
                | DeRef


data Expression = Empty
                | IntConst Int
                | FloatConst Float
                | StringConst String
                | Ident String
                | BinOp BinOperator Expression Expression
                | UnOp UnOperator Expression Bool //prefix or not
                | If Expression Expression Expression
                | While Expression Expression Bool //while vs. do while
                | Block List<Expression>
                | Call Expression List<Expression>
                | ...

Sebenarnya tidak perlu jauh lebih banyak untuk mewakili bahasa C.

Tapi sungguh, Anda dapat melakukan SEMUANYA dengan tipe data aljabar. Lisp membuktikan, Anda dapat melakukan segalanya dengan berpasangan dan ADT cukup memberikan cara yang lebih terperinci dan aman untuk pendekatan ini.

Tentu saja, jika Anda bertanya, "Apa yang dapat Anda lakukan dengan ADT, yang tidak dapat Anda lakukan dengan objek?", Jawabannya adalah "tidak ada". Hanya kadang-kadang (sebagian besar) Anda akan menemukan solusi pada ADT secara signifikan lebih sedikit bertele-tele, sedangkan yang berdasarkan objek bisa dibilang lebih fleksibel. Jadi untuk meletakkannya di pohon parse yang diwakili dengan ADT:

If(Call(Ident('likes_ADTs'),[Ident('you')]),
   Call(Ident('use_ADTs'),[Ident('you')]),
   Call(Ident('use_no_ADTs'),[Ident('you')]))
back2dos
sumber