Экзистенциальные типы. Написание экземпляра класса для гетерогенной карты

Используя следующие определения типов и классов, я не понимаю, почему я получаю ошибку при создании instance ниже.

Мне нужно, чтобы MyMap содержал карту разнородных значений.

{-# LANGUAGE ExistentialQuantification #-}
module Scratch.SO_ExtistentialTypes where

import Data.Map

type MyMap a = Map String a

class MyClass c where 
    getMyMap :: forall a. c -> MyMap a

data MyData = forall a. MyData {
    myMap ::  MyMap a
}

instance MyClass MyData where
    getMyMap = myMap -- <= ERROR

person Bruno Grieder    schedule 26.10.2012    source источник
comment
Чего вы пытаетесь добиться здесь? Потому что я серьезно сомневаюсь, что это хороший способ сделать это.   -  person C. A. McCann    schedule 26.10.2012
comment
@C.A.McCann type и class являются частью модуля, который определяет «API». dataи typeявляются (упрощенными) предварительными реализациями.   -  person Bruno Grieder    schedule 26.10.2012
comment
@C.A.McCann Другой способ выразить это так: как создать тип данных (MyData), который можно сделать экземпляром MyClass?   -  person Bruno Grieder    schedule 26.10.2012
comment
В нынешнем виде единственным разумным определением getMyMap является такое, которое игнорирует его ввод и каждый раз возвращает пустое Map. Я предполагаю, что это не то, что вы хотите, поэтому вы можете переосмыслить цель MyClass.   -  person C. A. McCann    schedule 26.10.2012
comment
Существует более ограниченное понятие гетерогенной карты, которое имеет смысл в типизированном параметре, где тип значения зависит от индекса ключа. У вас может быть data Map (k :: * -> *) = ..., а затем у вас будет такая функция, как lookup :: Ord1 k => Map k -> k a -> a. Теперь, если вы создадите экземпляр параметра Map для GADT, который уточняет его индексы, вы можете сопоставить разные ключи с разными типами значений. Я написал один из них некоторое время назад, но не могу найти его прямо сейчас. Хотя, возможно, это поможет вам прояснить, чего вы хотите.   -  person copumpkin    schedule 27.10.2012
comment
@copumkin Я сделал это новым вопросом   -  person Bruno Grieder    schedule 27.10.2012


Ответы (1)


Во-первых, forall здесь лишний:

class MyClass c where 
    getMyMap :: forall a. c -> MyMap a

Переменные типа без явного связывания универсально квантифицируются на самом внешнем уровне, так что это точно так же, как просто c -> MyMap a.

Кроме того, универсально квантифицированный тип, безусловно, не будет соответствовать экзистенциально квантифицированному типу. Тип getMyMap говорит, что при заданном значении типа c будет создано значение типа MyMap a для любого возможного выбора типа a. С другой стороны, метод доступа myMap говорит, что, учитывая значение типа MyData, он создаст значение типа MyMap a для некоторого конкретного, но неизвестного типа a.

Невозможно, чтобы развернутые экзистенциальные типы плавали сами по себе (для этого потребовался бы квантификатор exists, соответствующий forall), поэтому нет способа переписать тип getMyMap так, чтобы myMap был корректной реализацией.

Все, что вы можете сделать с чем-то, имеющим экзистенциальный тип, — это обернуть его обратно в другой тип данных, который скрывает квантор существования, или передать его функции, имеющей аргумент универсального кванторного типа. Например, вы можете использовать length в списке [a] с a экзистенциальным типом.

В вашем случае значения Map имеют экзистенциальный тип без какой-либо другой структуры или ограничений, поэтому они в значительной степени бесполезны и могут также быть ().

person C. A. McCann    schedule 26.10.2012
comment
Спасибо большое. Теперь я понимаю, что определение типа getMyMap выражает неверную вещь (оно возвращает карту универсально квантифицированного типа). Итак, как мне выразить в классе, что мне нужна функция, которая возвращает карту разнородных значений (если это вообще возможно)? - person Bruno Grieder; 26.10.2012
comment
@BGR: Выражение такого типа — это одно, но более важный вопрос заключается в том, чтобы фактически использовать структуру, содержащую значения разнородных типов. Тайные техники для работы с такими типами действительно существуют (ха, ха), но мое эмпирическое правило таково: если вам нужно спросить, как это сделать, не спрашивайте. Если вам нужен разумный API, который не вызывает ужасных затруднений в использовании, вам, вероятно, нужен другой дизайн. - person C. A. McCann; 26.10.2012
comment
:) Справедливо. Спасибо, что потратили время. - person Bruno Grieder; 26.10.2012
comment
@BGR: Вы, вероятно, могли бы получить несколько полезных советов, если бы вы опубликовали новый вопрос вроде «Я хочу сделать X, и мне сказали не использовать экзистенциальные типы, что мне делать вместо этого?». Прыгать в экзистенциальную кроличью нору — удивительно распространенная ошибка новичков, особенно тех, кто пришел из объектно-ориентированных языков без строгих статических типов. - person C. A. McCann; 26.10.2012
comment
справа здесь - person Bruno Grieder; 27.10.2012