[haskel] работа с existential типами

yroslavasako

Обнаружил замечательное расширение ghc, но не вполне понял, как его нужно использовать.
Есть объявление типа:
data Ord u => ExTest u = forall a. Ord a => ExTest u->aDS.Set a)

ghc жрёт это объявление типа нормально
пытаюсь написать функцию, которая возвращает первое значение в кортеже (u->a) - но никак не выходит, получаются одни ошибки. Подскажите, как это сделать правильно.

alfadred

Насколько я понимаю, этого сделать нельзя. Квантифицированный типы нужны для чего-то типа инкапсуляции.
Вот например, если есть
data Stream a = forall t. Stream t (t-> t) (t->a)

То можно сделать
get (Stream seed trans out) = out seed
next (Stream seed trans out) = Stream (trans seed) trans out

Но нельзя
state (Stream seed trans out) = seed

Потому что по типу параметра (Stream a) нельзя определить тип выходного значения, он квантифицирован.
См. пункт 7.4.4.4 мануала GHC

yroslavasako

можешь писать функции с объявлением типов? А то я новичок в хаскеле и без них путаюсь.
Сейчас я расскажу, что я хотел сделать в упрощённом виде.
Мне нужно уметь сравнивать с произвольным типом (для фильтрации). Для этого я ввёл тип, который хранит
1) способ приведения к одному виду: (u->a)
2) коллекцию типа a для сравнения: DS.Set a
Потом я хотел бы записать список этих сравнения [u->aDS.Set a)] и последовательно foldl фильтровать коллекцию на основе этих данных.
Что у меня не вышло: вытащить данные из existential type.

alfadred

можешь писать функции с объявлением типов? А то я новичок в хаскеле и без них путаюсь.
get :: Stream a -> a
next :: Stream a -> Stream a

А вот тип функции state не входит в систему типов Хаскеля. Тип
Stream a -> t
означает, что по любому представителю типа Stream a мы можем получить элемент любого типа t, что в этом случае нам не подходит.
Насчет задачи - если тебе в результате надо получать что-то содержащее в явном виде тип a, то его квантифицировать не надо.
Я бы написал что-нибудь такое:
{-# LANGUAGE MultiParamTypeClasses #-}

class Transform a b where
transform :: a -> b

filterLess :: (Ord u, Ord a, Transform u a) => u -> [a] -> [a]
filterLess e xs = filter (< transform e) xs

Но это если способ приведения одного типа к другому однозначен.

yroslavasako

да нет. Приводить можно к разным типам. Объявлять столько классов, сколько бывает разных v в (u->v)?

alfadred

да нет. Приводить можно к разным типам. Объявлять столько классов, сколько бывает разных v в (u->v)?
не классов, а инстансов
Вот пример:
{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances, IncoherentInstances #-}

module Main where

class Transform a b where
transform :: a -> b

filterLess :: (Ord u, Ord a, Transform u a) => u -> [a] -> [a]
filterLess e xs = filter (< transform e) xs

instance Transform Bool Integer where
transform x = if x then 1 else 0

instance Transform Bool String where
transform x = if x then "z" else ""

instance (Integral a) => Transform Integer a where
transform = fromInteger

instance (Show a) => Transform a String where
transform = show

instance (Integral a) => Transform a [] where
transform 0 = []
transform (i+1) = :(transform i)
transform _ = error "Negative integer transformed to []"

main :: IO
main = do
print $ filterLess True ([-3..3]::[Integer])
print $ filterLess 3 ["00a", "123", "300", "456"]
print $ filterLess 3 [[], [], [], []]

yroslavasako

всё, я решил проблему - отдельные функции не понадобились, т.к. везде подставил паттерн матчинг
Оставить комментарий
Имя или ник:
Комментарий: