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