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=…和使用(minBound
asArgTypeOf
r)和(maxBound
asArgTypeOf
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