Я хотел бы написать безопасную версию toEnum
:
safeToEnum :: (Enum t, Bounded t) => Int -> Maybe t
Наивная реализация:
safeToEnum :: (Enum t, Bounded t) => Int -> Maybe t
safeToEnum i =
if (i >= fromEnum (minBound :: t)) && (i <= fromEnum (maxBound :: t))
then Just . toEnum $ i
else Nothing
main = do
print $ (safeToEnum 1 :: Maybe Bool)
print $ (safeToEnum 2 :: Maybe Bool)
И это не работает:
safeToEnum.hs:3:21:
Could not deduce (Bounded t1) from the context ()
arising from a use of `minBound' at safeToEnum.hs:3:21-28
Possible fix:
add (Bounded t1) to the context of an expression type signature
In the first argument of `fromEnum', namely `(minBound :: t)'
In the second argument of `(>=)', namely `fromEnum (minBound :: t)'
In the first argument of `(&&)', namely
`(i >= fromEnum (minBound :: t))'
safeToEnum.hs:3:56:
Could not deduce (Bounded t1) from the context ()
arising from a use of `maxBound' at safeToEnum.hs:3:56-63
Possible fix:
add (Bounded t1) to the context of an expression type signature
In the first argument of `fromEnum', namely `(maxBound :: t)'
In the second argument of `(<=)', namely `fromEnum (maxBound :: t)'
In the second argument of `(&&)', namely
`(i <= fromEnum (maxBound :: t))'
Как я понимаю сообщение, компилятор не распознает, что minBound
и maxBound
должны выдавать точно такой же тип, как в типе результата safeToEnum
, несмотря на явное объявление типа (:: t
) , Есть идеи как это исправить?
решаемые
Работают как решения Camccann, так и Dave (хотя решение Dave нужно отрегулировать). Спасибо вам обоим (но я мог принять только одно). Рабочий пример с ScopedTypeVariables:
{-# LANGUAGE ScopedTypeVariables #-}
safeToEnum :: forall t . (Enum t, Bounded t) => Int -> Maybe t
safeToEnum i =
if (i >= fromEnum (minBound :: t)) && (i <= fromEnum (maxBound :: t))
then Just . toEnum $ i
else Nothing