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

use*_*886 1 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
Run Code Online (Sandbox Code Playgroud)

由于歧义检查,该代码无效.

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

chi*_*chi 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
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(甚至更多的代码).我不建议使用代理.