Почему в алгебраических типах данных, если я могу определить специальные функции «от» и «до» для двух типов, эти два типа можно считать равными?

Я читаю этот блог: http://chris-taylor.github.io/blog/2013/02/10/the-алгебра-оф-алгебраических-типовданных/

В нем говорится:

Однако, когда я говорю о равенстве, я не имею в виду равенство Haskell в смысле функции (==). Вместо этого я имею в виду, что два типа находятся во взаимно однозначном соответствии, то есть, когда я говорю, что два типа a и b равны, я имею в виду, что вы могли бы написать две функции

    from :: a -> b
    to   :: b -> a

которые объединяют значения a со значениями b, так что всегда выполняются следующие уравнения (здесь == является подлинным равенством в стиле Haskell):

    to (from a) == a
    from (to b) == b

И позже, есть много законов, основанных на этом определении:

Add Void a === a
Add a b === Add b a
Mul Void a === Void
Mul () a === a
Mul a b === Mul b a

Я не могу понять, почему мы можем смело получать эти законы, исходя из определения "равенство"? Можно ли использовать другие определения? Что мы можем сделать с этим определением? Имеет ли это смысл для систем типа Haskell?


person Freewind    schedule 03.08.2014    source источник


Ответы (3)


Термин, который автор использует, чтобы не «упоминать теорию категорий или продвинутую математику», — это количество элементов. Он определяет два типа как ===-равные друг другу, если они имеют одинаковую мощность, то есть, если существует столько же возможных значений одного, сколько и другого.

Потому что, если два типа имеют одинаковую мощность, между ними существует изоморфизм. Mul () Bool может быть другого типа, чем Bool, но членов одного типа ровно столько же, сколько и другого, и можно тривиально определить функцию, которая будет переходить от одного к другому или от другого к одному. (Не то, чтобы был только один такой изоморфизм — дело в том, что вы могли бы выбрать любой.)

Это не лучший подход. В принципе, он отлично работает для конечных множеств, но вводит неприятные побочные эффекты для бесконечных множеств, таких как Add Int Int === Int. Тем не менее, для базового описания сложения и умножения типов он, кажется, годится.

person Sneftel    schedule 03.08.2014
comment
Спасибо за отличный ответ. Чтобы понять это хорошо, т.е. cardinality, category theory, не могли бы вы порекомендовать мне какую-нибудь книгу? - person Freewind; 03.08.2014
comment
Кроме того, Add Int Int и Int не имеют одинакового равенства, поскольку Int является 32-битным целым числом. Для типа произвольно больших чисел вы должны написать Integer. - person ThreeFx; 03.08.2014
comment
@Freewind Концептуальная математика: первое введение в категории — это хорошее, легко читаемое введение в теорию категорий, которое не требует особых математических знаний. Однако из-за этого он не слишком глубоко проникает в тему, но это хорошее начало. Тем не менее, он охватывает идею изоморфизма (и некоторые связанные идеи). Кроме того, вы случайно не тот самый Sneftel из GDNet, не так ли? Маленький мир - person David Young; 04.08.2014
comment
@Freewind Кроме того, вы можете найти идею отношения эквивалентности и попытаться доказать, что это определение равенства удовлетворяет законам отношения эквивалентности в качестве упражнения. - person David Young; 04.08.2014
comment
@Freewind О, также есть книга «Теория гомотопических типов», в которой подробно рассказывается о том, что означает, что два типа равны друг другу (значения тоже), и о последствиях этого (и о том, как эта идея на самом деле имеет сильную связь с идеей гомотопии из топологии и теории гомотопий). Она более глубокая, но значительно более сложная, чем концептуальная математика (я все еще работаю над теорией гомотопических типов, и у меня есть некоторые трудности), но в конечном итоге вам может быть интересно взглянуть на нее. Я определенно предлагаю начать с концептуальной математики. - person David Young; 04.08.2014
comment
@DavidYoung, большое спасибо! Я найду эти книги, надеюсь, я смогу узнать больше о типах - person Freewind; 04.08.2014
comment
@DavidYoung Да, это я. - person Sneftel; 04.08.2014

Неформально говоря, когда две математические структуры A,B имеют две "хорошие" функции from,to, удовлетворяющие from . to == id и to . from == id, структуры A,B называются изоморфными.

Фактическое определение «хорошей» функции зависит от типа имеющейся структуры (и иногда разные определения «хорошей» приводят к различным понятиям изоморфизма).

Идея изоморфных структур заключается в том, что они «работают» примерно одинаково. Например, рассмотрим структуру A, созданную логическими значениями True,False с &&,|| в качестве операций. Пусть тогда структура B состоит из двух натуральных1,0 с min,max в качестве операций. Это разные структуры, но они имеют одни и те же правила. Например, True && x == x и 1 `min` x == x для всех x. A и B изоморфны: функция to будет отображать True в 1 и False в 0, а from будет выполнять противоположное отображение.

(Обратите внимание, что хотя мы могли бы сопоставить True с 0 и False с 1, и мы все равно получили бы from . to == id и его двойник, это сопоставление не будет считаться «хорошим», поскольку оно не сохранит структуру: например, to (True && x) == to x еще to (True && x) == to True `min` to x == 0 `min` to x == 0 .)

Другой пример в другой постановке: пусть A — это круг на плоскости, а B — это квадрат на этой плоскости. Затем можно определить непрерывные сопоставления to,from между ними. Это можно сделать с любыми двумя «замкнутыми петлями», грубо говоря, которые можно назвать изоморфными. Вместо этого окружность и фигура «восьмерка» не допускают таких непрерывных отображений: самопересекающаяся точка в «восьмерке» не может быть отображена в любую точку окружности непрерывным образом (грубо говоря, от нее отходят четыре «пути»). , а точки в окружности имеют только два таких «пути»).

Аналогичным образом в Haskell типы называются изоморфными, когда между ними существуют две определяемые в Haskell функции from,to, удовлетворяющие приведенным выше правилам. Здесь «хорошая» функция просто означает, что ее можно определить в Haskell. Связанный веб-блог показывает несколько таких изоморфных типов. Вот еще один пример с использованием рекурсивных типов:

List1 a = Add Unit (Mul a (List1 a))
List2 a = Add Unit (Add a (Mul a (Mul a (List2 a))))

Интуитивно первый читается так: «список — это либо пустой список, либо пара, состоящая из элемента и списка». Второй читается так: «список — это либо пустой список, либо один элемент, либо тройное соединение элемента, другого элемента и списка». Можно конвертировать между ними, обрабатывая элементы по два за раз.

Другой пример:

Tree a = Add Unit (Mul a (Mul (Tree a) (Tree a)))

Вы можете доказать, что тип Tree Unit изоморфен List1 (Tree Unit), используя алгебраические законы, найденные в блоге. Ниже = обозначает изоморфизм.

List1 (Tree Unit)
-- definition of List1 a
= Add Unit (Mul (Tree Unit) (List1 (Tree Unit))) 
-- by inductive hypothesis, the inner `List1 (Tree Unit)` is isomorphic to `Tree Unit`
= Add Unit (Mul (Tree Unit) (Tree Unit))
-- definition of Tree a
= Tree Unit

Приведенный выше набросок доказательства индуцирует функцию to следующим образом.

data Add a b = InL a | InR b
data Mul a b = P a b
type Unit = ()
newtype List1 a = List1 (Add Unit (Mul a (List1 a)))
newtype Tree a  = Tree  (Add Unit (Mul a (Mul (Tree a) (Tree a))))

to :: List1 (Tree Unit) -> Tree Unit
to (List1 (InL ())) = Tree (InL ())
to (List1 (InR (P t ts))) = Tree (InR (P () (P t (to ts))))

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

Написание from оставлено в качестве упражнения :-P

person chi    schedule 03.08.2014
comment
Можно привести веские доводы в пользу того, что разумно обозначать понятия изоморфизма по-разному в зависимости от того, что вы называете хорошим — и действительно, это делается во многих областях математики, например, в непрерывном случае его очень редко называют изоморфным. но гомеоморфны; если вы добавите аналитичность, это будет диффеоморфно и т.д.. - person leftaroundabout; 04.08.2014

Почему в алгебраических типах данных, если я могу определить специальные функции from и to для двух типов, эти два типа можно считать равными?

Что ж, здесь лучше использовать термин не "равный", а скорее изоморфный. Дело в том, что когда два типа изоморфны, они в принципе взаимозаменяемы друг с другом; любая программа, написанная в терминах A, в принципе может быть написана в терминах B, без изменения смысла программы. Предположим, у вас есть:

from :: A -> B
to   :: B -> A

и эти две функции составляют изоморфизм, то есть:

to (from a) == a
from (to b) == b

Теперь, если у вас есть функция, которая принимает A в качестве аргумента, вы можете, например, написать аналог, который вместо этого принимает B в качестве аргумента:

foo :: B -> Something
foo = originalFoo . from
    where originalFoo :: A -> Something
          originalFoo a = ...

И для любой функции, которая производит A, вы можете сделать это аналогичным образом:

bar :: Something -> B
bar = to . originalBar
    where originalBar :: Something -> A
          originalBar something = ...

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

person Luis Casillas    schedule 04.08.2014