Каковы виды использования алгебраических типов данных?


16

Я читаю об алгебраических типах данных (благодаря Ричарду Минериху я нашел это отличное объяснение концепции). Хотя я думаю, что понимаю понятие типов сумм, типов продуктов и т. Д., Я не совсем понимаю, как алгебраические типы данных полезны помимо определения соответствия шаблонам. Что еще можно сделать с помощью ADT помимо сопоставления с образцом?


РЕДАКТИРОВАТЬ: Я не спрашиваю, что может сделать разработчик с ADT, что не может быть сделано с объектами. Я спрашиваю, есть ли другие операции, которые допускает ADT; Например, можно ли сделать дополнительные рассуждения о типах участвующих, если используются ADT? Облегчают ли ADT какой-то тип анализа, который был бы невозможен без них?


2
Что вы можете делать с объектами, кроме вызова методов?

1
ADT фактически относится к «абстрактному типу данных», а не к алгебраическим типам данных.
Рейн Хенрикс

4
@ Rein: может относиться к любому из них в зависимости от контекста.
sepp2k

4
@ Rein: Это действительно так (что я нахожу весьма удивительным, если честно): однако в статье в Википедии для ADT перечислены как абстрактный тип данных, так и алгебраический тип данных в качестве возможных значений. А ADT очень часто используется в качестве сокращения для алгебраических типов данных, например, в списке рассылки Haskell и канале IRC.
sepp2k

1
@ Рейн, я знаю - просто надоело набирать «Алгебраический тип данных» снова и снова, и я подумал, что люди смогут понять, о чем я говорил, учитывая контекст.
Онорио Катеначчи

Ответы:


10

Алгебраические типы данных отличаются тем, что они могут быть построены из нескольких типов «вещей». Например, Дерево может не содержать ничего (Пусто), Лист или Узел.

data Tree = Empty
          | Leaf Int
          | Node Tree Tree

Поскольку узел состоит из двух деревьев, алгебраические типы данных могут быть рекурсивными.

Сопоставление с образцом позволяет деконструировать алгебраические типы данных таким образом, чтобы обеспечить безопасность типов. Рассмотрим следующую реализацию глубины и ее эквивалент псевдокода:

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

по сравнению с:

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)

Это имеет недостаток, заключающийся в том, что программист должен помнить регистр Empty перед Leaf, чтобы поле field1 не было доступно для пустого дерева. Аналогично, регистр Leaf должен быть объявлен перед регистром Node, чтобы поле 2 не было доступно на Leaf. Таким образом, безопасность типов, таким образом, не поддерживается языком, а скорее накладывает дополнительную когнитивную нагрузку на программиста. Кстати, я беру эти примеры прямо со страниц Википедии.

Конечно, языковой набор утки может сделать что-то вроде этого:

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

Таким образом, алгебраические типы данных не могут быть строго лучше, чем их эквивалент ООП, но они предоставляют другой набор напряжений для работы при создании программного обеспечения.


9

Я не уверен , что объяснение это все , что отлично.

Алгебраические типы данных используются для создания структур данных, таких как списки и деревья.

Например, деревья разбора легко представляются алгебраическими структурами данных.

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

На самом деле это не займет намного больше времени для представления языка Си.

Но на самом деле вы можете делать ВСЕ с алгебраическими типами данных. Lisp доказывает, что вы можете делать все с помощью пар и ADT, просто предоставляя более детальный и безопасный для этого способ.

Конечно, если вы спросите: «Что вы можете сделать с ADT, что вы не можете сделать с объектами?», Ответ будет «ничего». Только иногда (в основном) вы обнаружите, что решения для ADT значительно менее многословны, в то время как решения, основанные на объектах, возможно, более гибкие. Итак, чтобы поместить его в дерево разбора, представленное с помощью ADT:

If(Call(Ident('likes_ADTs'),[Ident('you')]),
   Call(Ident('use_ADTs'),[Ident('you')]),
   Call(Ident('use_no_ADTs'),[Ident('you')]))
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.