Можно и по другому поступить: class StackSlots a size | a -> size instance StackSlots Char (S Z) instance StackSlots Int (S Z) instance StackSlots a size => StackSlots (Maybe a) (S size) class StackSlots a (S Z) => StackSlot a
type instance Fit Char = Yes type instance Fit Int = Yes type instance Fit (Maybe a) = No
test :: (Fit a ~ Yes) => a -> a test = id
Кстати, есть такая прикольная практика - partial signature, может знаешь, а если нет, то может окажется полезным. Смысл такой - тебе не хочется выписывать весь тип самому, но некоторые ограничения ты прописать хочешь. Например, для функции test ты хочешь прописать ограничение Fit a ~ Yes
-- определяем ограничение, которое мы будем добавлять к нужным нам функциям (test, dup, over...) fitParam :: (Fit a ~ Yes) => a -> b fitParam = undefined
-- добавляем ограничение test a | False = fitParam a -- основная реализация test a = a
Выразительнее, потому что они предназначены для подобных выражений мысли. Всё таки в подобном использовании классов чувствуется, что этот инструмент совсем для другого задумывался.
Равенство типов - это вот это?
type family Equal a type instance Equal a = a
test :: (Equal a ~ b) => a -> b -> (a, b) test = (,)
Что такое HList lookup посмотрю сначала, потом отвечу.
Посмотрел, с первого раза кажется, что hlist lookup не запишется, потому что нельзя навешивать контексты на type instances. Когда они уже это добавят!
Но я бы это делал на HList, который имеет только Eq элементы, и использовал cast и (==). Так проще всего, IMHO. А вообще надо подумать, но чуть позже :)
Э, погоди! Если это лукап по типу, а не по ключу, то проблема именно в недоразвитости type family (нельзя добавить контекст). Ну нет у open functions возможности FlexibleTypeInstances и OverlappedTypeInstances :)
Поэтому классы вынужденная мера и здесь уже можно использовать не fundeps, а associated types.
Reply
Reply
Reply
class StackSlots a size | a -> size
instance StackSlots Char (S Z)
instance StackSlots Int (S Z)
instance StackSlots a size => StackSlots (Maybe a) (S size)
class StackSlots a (S Z) => StackSlot a
Это даже логичней.
Reply
{-# LANGUAGE TypeFamilies, EmptyDataDecls #-}
data Yes
data No
type family Fit a :: *
type instance Fit Char = Yes
type instance Fit Int = Yes
type instance Fit (Maybe a) = No
test :: (Fit a ~ Yes) => a -> a
test = id
Кстати, есть такая прикольная практика - partial signature, может знаешь, а если нет, то может окажется полезным. Смысл такой - тебе не хочется выписывать весь тип самому, но некоторые ограничения ты прописать хочешь. Например, для функции test ты хочешь прописать ограничение Fit a ~ Yes
-- определяем ограничение, которое мы будем добавлять к нужным нам функциям (test, dup, over...)
fitParam :: (Fit a ~ Yes) => a -> b
fitParam = undefined
-- добавляем ограничение
test a | False = fitParam a
-- основная реализация
test a = a
Это меня nealar в своё время натолкнул
http://okmij.org/ftp/Haskell/partial-signatures.lhs
Reply
Fit a = Yes/No хуже учёта размеров. Размер можно потом использовать в своих целях, Yes/No слишком ограничены.
Reply
Reply
Запиши равенство типов на type families. Запиши HList lookup.
У меня не получается.
Reply
Равенство типов - это вот это?
type family Equal a
type instance Equal a = a
test :: (Equal a ~ b) => a -> b -> (a, b)
test = (,)
Что такое HList lookup посмотрю сначала, потом отвечу.
Reply
Но я бы это делал на HList, который имеет только Eq элементы, и использовал cast и (==). Так проще всего, IMHO. А вообще надо подумать, но чуть позже :)
Reply
Так что вот тебе и ограничения в выразительности.
Reply
Поэтому классы вынужденная мера и здесь уже можно использовать не fundeps, а associated types.
Reply
Реализация, правда, вывернется, но над этим тоже можно подумать. Кстати, тут достаточно просто ADT.
Reply
Reply
Я имею в виду как-то так
{-# LANGUAGE GADTs #-}
data Fit a where
IntFit :: Int -> Fit Int
CharFit :: Char -> Fit Char
test :: Fit a -> a
test (IntFit x) = x
test (CharFit x) = x
Reply
class Fit a where fit :: forall p. p Int -> p Char -> p a
Reply
Leave a comment