haskell中具有最小长度和最大长度的类型

时间:2018-04-24 21:16:40

标签: haskell

有没有一种简单的方法可以做这样的事情?

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

由于模糊检查,该代码无法正常工作。

我想这样做是为了验证任何类型的用户输入,但也许我走得太远了?

1 个答案:

答案 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(甚至更多代码)。我不建议使用代理。