Công dụng của các kiểu dữ liệu đại số là gì?


16

Tôi đang đọc về các kiểu dữ liệu đại số (nhờ Richard Minerich tôi đã tìm thấy lời giải thích tuyệt vời này về khái niệm này). Mặc dù tôi nghĩ rằng tôi hiểu khái niệm về loại tổng và loại sản phẩm, v.v., điều tôi không hiểu lắm là làm thế nào Kiểu dữ liệu đại số hữu ích ngoài việc chỉ định khớp mẫu. Những điều khác người ta có thể làm với ADT ngoài việc khớp mẫu?


EDIT: Tôi không hỏi nhà phát triển có thể làm gì với ADT mà không thể thực hiện được với các đối tượng. Tôi đang hỏi nếu có các hoạt động khác mà ADT cho phép; ví dụ, người ta có thể làm lý do bổ sung về các loại liên quan nếu ADT được sử dụng không? Do ADT tạo điều kiện cho một số loại phân tích không thể thực hiện được nếu không có chúng?


2
Bạn có thể làm gì với các đối tượng ngoại trừ các phương thức gọi?

1
ADT thực sự đề cập đến "kiểu dữ liệu trừu tượng", không phải kiểu dữ liệu đại số .
Rein Henrichs

4
@Rein: Nó có thể đề cập đến tùy thuộc vào ngữ cảnh.
sepp2k

4
@Rein: Thực sự (điều mà tôi thấy khá ngạc nhiên khi thành thật): Tuy nhiên, bài viết trên wikipedia cho ADT liệt kê cả Kiểu dữ liệu trừu tượng và Kiểu dữ liệu đại số là ý nghĩa có thể. Và ADT thường được sử dụng như một từ viết tắt cho các loại dữ liệu đại số trên ví dụ như danh sách gửi thư Haskell và kênh IRC.
sepp2k

1
@Rein, tôi biết - tôi cảm thấy mệt mỏi khi phải gõ "Kiểu dữ liệu đại số" nhiều lần và tôi cho rằng mọi người sẽ có thể hiểu những gì tôi đang đề cập đến trong bối cảnh.
Onorio Catenacci

Câu trả lời:


10

Các kiểu dữ liệu đại số khác biệt ở chỗ chúng có thể được xây dựng từ một số loại "vật". Chẳng hạn, Cây có thể chứa không có gì (Trống), Lá hoặc Nút.

data Tree = Empty
          | Leaf Int
          | Node Tree Tree

Do một nút bao gồm hai cây, nên các kiểu dữ liệu đại số có thể được đệ quy.

Khớp mẫu cho phép các kiểu dữ liệu đại số được giải cấu trúc theo cách duy trì sự an toàn của kiểu. Hãy xem xét việc thực hiện độ sâu sau đây và mã giả tương đương của nó:

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

so với:

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)

Điều này có nhược điểm là lập trình viên phải nhớ trường hợp rỗng trước Lá để trường1 không được truy cập trên cây rỗng. Tương tự, trường hợp Lá phải được khai báo trước trường hợp Nút để trường 2 không được truy cập trên Lá. Do đó, an toàn kiểu do đó không được duy trì bởi ngôn ngữ mà thay vào đó áp đặt tải nhận thức bổ sung cho lập trình viên. Nhân tiện, tôi lấy các ví dụ này trực tiếp từ các trang wikipedia.

Tất nhiên, một ngôn ngữ gõ vịt có thể làm một cái gì đó như thế này:

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

Vì vậy, các loại dữ liệu đại số có thể không hoàn toàn tốt hơn so với tương đương OOP của chúng, nhưng chúng cung cấp một tập hợp căng thẳng khác nhau để làm việc khi xây dựng phần mềm.


9

Tôi không phải như vậy chắc chắn lời giải thích là tất cả những điều đó tuyệt vời.

Các kiểu dữ liệu đại số được sử dụng để tạo cấu trúc dữ liệu, chẳng hạn như danh sách và cây.

Ví dụ, cây phân tích được biểu diễn dễ dàng với các cấu trúc dữ liệu đại số.

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>
                | ...

Nó thực sự sẽ không mất nhiều hơn nữa để đại diện cho ngôn ngữ C.

Nhưng thực sự, bạn có thể làm về MỌI THỨ với các kiểu dữ liệu đại số. Lisp chứng minh, bạn có thể làm mọi thứ với các cặp và ADT chỉ đơn giản là cung cấp một cách an toàn hơn và chi tiết hơn cho phương pháp này.

Tất nhiên, nếu bạn hỏi, "Bạn có thể làm gì với ADT, bạn không thể làm gì với các đối tượng?", Câu trả lời là "không có gì". Chỉ đôi khi (hầu hết) bạn sẽ thấy các giải pháp trên ADT ít dài hơn đáng kể, trong khi những giải pháp dựa trên các đối tượng được cho là linh hoạt hơn. Vì vậy, để đặt nó trong một cây phân tích đại diện với ADT:

If(Call(Ident('likes_ADTs'),[Ident('you')]),
   Call(Ident('use_ADTs'),[Ident('you')]),
   Call(Ident('use_no_ADTs'),[Ident('you')]))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.