Я хочу проверить, правильно ли я реализовал перечисление. То есть я хочу подтвердить, что
(toEnum . fromEnum) a = a
(fromEnum . toEnum) z = z
где a — экземпляр моего перечисляемого типа, а z — Int. Первый случай в порядке.
> (toEnum . fromEnum) Green == Green
True
Можно написать функцию, возвращающую логическое значение, например,
convertsFromTo :: (Enum a, Eq a) => a -> Bool
convertsFromTo a = (toEnum . fromEnum) a == a
и используется
> convertsFromTo Green
True
Второй случай сложнее, так как компилятору нужна подсказка типа, чтобы узнать тип значения, которое должно быть создано из целого числа.
> fromEnum (toEnum 1 :: Colour) == 1
True
Есть ли способ передать подсказку типа функции?
convertsToFrom :: ??? -> Int -> Bool
convertsToFrom ??? z = fromEnum (toEnum z :: ???) == z
В качестве альтернативы, есть ли лучшее решение, чем вызов toEnum
вне функции?
convertsToFrom :: Enum a => a -> Int -> Bool
convertsToFrom a z = fromEnum a == z
> convertsToFrom (toEnum 1 :: Colour) 1
True
Для полноты,
data Colour = Red | Green | Blue deriving (Eq)
instance Enum Colour where
fromEnum Red = 0
fromEnum Green = 1
fromEnum Blue = 2
toEnum 0 = Red
toEnum 1 = Green
toEnum 2 = Blue
Да, вы можете работать с TypeApplications [ghc-doc]:
{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
convertsToFrom :: forall a . Enum a => Int -> Bool
convertsToFrom z = fromEnum (toEnum z :: a) == z
то вы можете использовать это, например, с convertsToFrom @Colour
.
это волшебство :D Большое спасибо! Между прочим, модуль, вызывающий
convertsToFrom
, нуждался в TypeApplications, а модуль, объявляющий необходимые ScopedTypeVariables и AllowAmbiguousTypes.