有没有一种简单的方法可以做这样的事情?
import Data.Int (Int64)
class BoundedLen a where
minLen :: Int64
maxLen :: Int64
len :: a -> Int64
data LenError = TooShort | TooLong
validateLen :: BoundedLen a => a -> Either LenError a
validateLen x
| minLen > len x = Left TooShort
| maxLen < len x = Left TooLong
| otherwise = Right x
由于模糊检查,该代码无法正常工作。
我想这样做是为了验证任何类型的用户输入,但也许我走得太远了?
答案 0 :(得分:5)
现代的方法是打开一堆扩展程序:ScopedTypeVariables, AmbiguousTypes, TypeApplications
。
validateLen :: forall a. BoundedLen a => a -> Either LenError a
validateLen x
| minLen @a > len x = Left TooShort
| maxLen @a < len x = Left TooLong
| otherwise = Right x
或者,您可以为方法添加伪参数,以消除歧义。
class BoundedLen a where
minLen :: a -> Int64 -- the argument is not really used
maxLen :: a -> Int64 -- the argument is not really used
len :: a -> Int64
validateLen :: BoundedLen a => a -> Either LenError a
validateLen x
| minLen x > len x = Left TooShort
| maxLen x < len x = Left TooLong
| otherwise = Right x
这里的情况并不算太糟糕,但仅仅传递x
消除歧义类型感觉非常不自然,因为x
的价值无关紧要。
也可以使用代理,如
class BoundedLen a where
minLen :: proxy a -> Int64
maxLen :: proxy a -> Int64
len :: a -> Int64
validateLen :: forall a. BoundedLen a => a -> Either LenError a
validateLen x
| minLen (Proxy :: Proxy a) > len x = Left TooShort
| maxLen (Proxy :: Proxy a) < len x = Left TooLong
| otherwise = Right x
但这比第一种选择使用起来更麻烦,仍然需要ScopedTypeVariables
(甚至更多代码)。我不建议使用代理。