Haskell 安全多态性toEnum
我想写一个安全版本的Haskell 安全多态性toEnum,haskell,polymorphism,Haskell,Polymorphism,我想写一个安全版本的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)) th
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)
您需要使用作用域类型变量
{-# LANGUAGE ScopedTypeVariables #-}
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)
{-#语言范围的TypeVariables}
safeToEnum::(枚举t,有界t)=>Int->Maybe t
安菲托纳姆一号=
如果(i>=fromnum(minBound::t))&(i作用域类型变量在这里不是必需的,那么您只需要向GHC说明,您希望所有Enum
内容都是相同的类型。通过将它们全部传递给显式接受相同类型的各种Enum
的函数,这很容易做到。有一种方法:
enumIfBetween :: (Enum a) => a -> a -> Int -> Maybe a
enumIfBetween a z x = let a' = fromEnum a
z' = fromEnum z
in if a' <= x && x <= z'
then Just $ toEnum x
else Nothing
safeToEnum i = enumIfBetween minBound maxBound i
main = do
print $ (safeToEnum 1 :: Maybe Bool)
print $ (safeToEnum 2 :: Maybe Bool)
使用相同原理的更通用的解决方案是标准库函数asTypeOf
,它与const
具有相同的行为,但要求两个参数的类型相同:
safeToEnum :: (Enum t, Bounded t) => Int -> Maybe t
safeToEnum i = let r = toEnum i
max = maxBound `asTypeOf` r
min = minBound `asTypeOf` r
in if i >= fromEnum min && i <= fromEnum max
then Just r
else Nothing
safeToEnum::(枚举t,有界t)=>Int->Maybe t
安全数i=设r=安全数i
max=maxBound`asTypeOf`r
min=minBound`asTypeOf`r
在if i>=fromEnum min&&i仍然获取无法从上下文()推断(有界t1)
.GHC 6.12.1.OK。这起作用:safeToEnum::forall t.(枚举t,有界t)=>Int->Maybe t
。谢谢你。你可以通过添加一个助手组合符,比如:asArgTypeOf::a->fa->a;asArgTypeOf=const,然后通过safeToEnum i=r,其中r=…和使用(minBoundasArgTypeOf
r)和(maxBoundasArgTypeOf
r)来解决使用范围型变量的问题.我喜欢你的解决方案。r
没有在asTypeOf
(第二版)中进行实际评估,这很好。@jetxee:好吧,如果你真的使用它,肯定会进行评估……如果结果是什么都没有
,这当然不会发生。懒惰不是很好吗?
enumIfBetween :: (Enum a) => a -> a -> Int -> Maybe a
enumIfBetween a z x = let a' = fromEnum a
z' = fromEnum z
in if a' <= x && x <= z'
then Just $ toEnum x
else Nothing
safeToEnum i = enumIfBetween minBound maxBound i
main = do
print $ (safeToEnum 1 :: Maybe Bool)
print $ (safeToEnum 2 :: Maybe Bool)
> main
Just True
Nothing
safeToEnum :: (Enum t, Bounded t) => Int -> Maybe t
safeToEnum i = let r = toEnum i
max = maxBound `asTypeOf` r
min = minBound `asTypeOf` r
in if i >= fromEnum min && i <= fromEnum max
then Just r
else Nothing