有没有一种简单的方法来做这样的事情?
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
Run Code Online (Sandbox Code Playgroud)
由于歧义检查,该代码无效.
我想这样做来验证任何类型的用户输入,但也许我走得太远了?
现代的方式是打开一堆扩展: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
Run Code Online (Sandbox Code Playgroud)
或者,您可以向方法添加伪参数,以消除歧义.
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
Run Code Online (Sandbox Code Playgroud)
这在这里并不算太糟糕,但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
Run Code Online (Sandbox Code Playgroud)
但这比第一种选择使用起来更麻烦,并且仍然需要ScopedTypeVariables(甚至更多的代码).我不建议使用代理.