Функции как типы в haskell
У меня путаница с использованием типов, которые являются функциями.
Скажем, я хочу реализовать словарь, который при задании a и b возвращает Maybe b.
type Dict a b = a->Maybe b
Как я могу реализовать функцию вставки для этого словаря?
insertDict :: (Eq a) => a -> b -> (Dict a b)-> (Dict a b)
Я придумал следующее:
insertDict x y mydict = \a->Just y
но это неверно и отменит предыдущий словарь.
Ответы
Ответ 1
Вы можете использовать шаблон "цепочка ответственности": функция вставки проверяет, соответствует ли аргумент результату Dict
его собственному ключу, иначе он делегирует предыдущий Dict
, который был получен как аргумент.
type Dict a b = a -> Maybe b
insertDict :: (Eq a) => a -> b -> Dict a b -> Dict a b
-- Note that the k' is the argument of the result dict function
insertDict k v dict k' = if k == k' then Just v else dict k'
emptyDict :: Dict a b
emptyDict _ = Nothing
Некоторые примеры в ghci:
Λ insertDict 'a' (1::Int) emptyDict $ 'a'
Just 1
Λ insertDict 'b' 2 (insertDict 'a' (1::Int) emptyDict) $ 'a'
Just 1
Λ insertDict 'b' 2 (insertDict 'a' (1::Int) emptyDict) $ 'x'
Nothing
Представление карт как функций хорош в первом приближении, но это представление имеет ряд недостатков:
- Сложность поиска значения линейна по количеству ключей.
- Функции довольно "непрозрачные", что означает, что вы не можете проверить или сериализовать карту, как вы могли бы сделать, если бы вы использовали тип данных .
Ответ 2
Вот один из способов, который вы можете использовать для написания таких функций самостоятельно. Сначала напишите сигнатуру типа:
insertDict :: (Eq k) => k -> v -> Dict k v -> Dict k v
Для ясности здесь использовались k
и v
для "ключа" и "значения". Затем начните с написания реализации как отверстия:
insertDict key value dict
= _
Компилятор (или GHCi) должен дать вам сообщение типа "Найденное отверстие: _ :: Dict k v
[...] Релевантные привязки включают в себя: dict :: Dict k v
, value :: v
, key :: k
. Итак, вы видите, что можете просто вернуться dict
, потому что тип совпадает, но это игнорирует key
и value
.
Поскольку вы знаете, что Dict k v
- это тип функции, вы можете добиться прогресса, добавив лямбда с другим отверстием, чтобы узнать, что предлагает компилятор:
insertDict key value dict
= \ key' -> _
Теперь мы имеем _ :: Maybe v
, value :: v
, key' :: k
, key' :: k
, dict :: Dict k v
. Мы всегда могли бы возвращать Just value
, но, как вы заметили, это не делает то, что мы хотим - оно представляет собой словарь, который всегда отвечает "Да, этот ключ находится в словаре, а его значение - value
" для любой клавиши, которую вы задаете! (Это полезная вещь, которую можно представить, ее просто не было написано.)
Итак, это не похоже, что мы можем добиться прогресса только с этими, но подождите, у нас также есть ограничение Eq k
! И только две вещи, которые мы можем сравнить: key
и key'
, поэтому давайте разложим это на if
с помощью ==
:
insertDict key value dict
= \ key' -> if key == key' then _1 else _2
Теперь компилятор сообщает _1 :: Maybe v
и _2 :: Maybe v
. Что мы должны возвращать в каждом из этих случаев? Давайте рассмотрим некоторые примеры того, как эта функция используется на самом деле: если вы посмотрите ключ в словаре после вставки пары ключ-значение, вы должны, естественно, найти значение:
(insertDict key value dict) key == Just value
----------
Итак, для _1
мы можем написать Just value
:
insertDict key value dict
= \ key' -> if key == key' then Just value else _2
----------
Если вы посмотрите на другой ключ, чем тот, который вы только что вставили, то самая последняя вставленная пара ключ-значение не имеет значения; он должен искать ключ дальше в словаре:
(insertDict key value dict) key' == dict key' -- If key /= key'
---------
Итак, для _2
мы можем написать dict key'
:
insertDict key value dict
= \ key' -> if key == key' then Just value else dict key'
---------
И все было сделано!: D
Эта комбинация программирования, ориентированного на тип и эквациональное рассуждение, очень полезна при написании в Haskell, особенно для таких полиморфных функций, которые имеют ограниченное число возможных (нормальных) реализаций.