Как распаковать haskell экзистенциальный тип?

Экспериментирование с экзистенциальными типами. Кажется, отличный способ получить некоторую гибкость типа.

Я поражаю проблему с распаковыванием экзистенциального типа после того, как я обернул его. Мой код следующим образом:

{-# LANGUAGE ExistentialQuantification #-}

class Eq a => Blurb a
data BlurbBox = forall a . Blurb a => BlurbBox a

data Greek = Alpha | Beta deriving Eq
instance Blurb Greek

data English = Ay | Bee deriving Eq
instance Blurb English

box1 :: BlurbBox
box1 = BlurbBox Alpha

box2 :: BlurbBox
box2 = BlurbBox Ay

main = do
    case box1 of
        BlurbBox Alpha -> putStrLn "Alpha"
        BlurbBox Beta -> putStrLn "Beta"
        BlurbBox Ay -> putStrLn "Ay"
        BlurbBox Bee -> putStrLn "Bee"

Этот код компиляции до основного, затем жалуется на тип Альфы BlurbBox. Как я иду о распаковывании/распаковке экзистенциального типа?

16
задан me2 19 February 2010 в 23:18
поделиться

3 ответа

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

Вы можете лучше понять это, если поймете, что

data BlurbBox = forall a . Blurb a => BlurbBox a

переводится в

type BlurbBox = forall b . (forall a . Blurb a => a -> b) -> b

, то есть BlurbBox - это то, что, учитывая полиморфную функцию, которая работает абсолютно для всех Blurbs, может использоваться для получения результата применения этой функции. к какой-то (неизвестной) аннотации.

Таким образом, аналогично тому, как вы не можете написать функцию типа f :: a -> Int и иметь f String = 5 и f Bool = 3, вы не можете отправить по типу 'a' в BlurbBox.

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

16
ответ дан 30 November 2019 в 17:39
поделиться

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

Итак, в вашем примере вашим «интерфейсом» является BlurbBox , и вы могли бы использовать его для единообразного применения некоторого метода к разным BlurbBox, не беспокоясь о том, какой внутренний тип a (например, если Blurb подклассы Показать , тогда вы можете иметь [BlurbBox] и печатать каждый элемент списка, не зная точный внутренний тип каждого BlurbBox в списке).

4
ответ дан 30 November 2019 в 17:39
поделиться

Вы не можете * специализировать тип после того, как спрятали его. Добавьте ограничение или метод в Blurb , если вам нужна такая операция.

-- choose one
class (Eq a, Show a) => Blurb a where
    printBlurb :: a -> IO ()
instance Blurb Greek where
    printBlurb Alpha = putStrLn "Alpha"
...

class (Eq a, Show a) => Blurb a
data Greek deriving (Eq, Show)
...

data BlurbBox = forall a. (Blurb a, Show a) => BlurbBox a
data Greek deriving (Eq, Show)
...

* Я бы очень рекомендовал против этого, но если вы действительно хотите…

{-# LANGUAGE DeriveDataTypeable #-}
import Data.Dynamic

data Greek = Alpha | Beta deriving (Eq, Typeable)
data English = Ay | Bee deriving (Eq, Typeable)

box1 :: Dynamic
box1 = toDyn Alpha

box2 :: Dynamic
box2 = toDyn Ay

main = do
    case fromDynamic box1 of
      Just Alpha -> putStrLn "Alpha"
      Just Beta -> putStrLn "Beta"
      Nothing -> case fromDynamic box1 of
        Just Ay -> putStrLn "Ay"
        Just Bee -> putStrLn "Bee"
11
ответ дан 30 November 2019 в 17:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: