Haskell 如何获取函数类型定义中声明的枚举类型的最小值?

Haskell 如何获取函数类型定义中声明的枚举类型的最小值?,haskell,Haskell,假设我想定义一个函数,它使用为给定类型定义的一个常量。我试过: minValue :: (Enum a,Bounded a) => a minValue = minBound::a 但是函数定义不知道a是Enum类型,因为声明中指定了Enum类型。两个合理的答案: 删除内部类型签名 minValue = minBound 虽然这是可行的,但它不能很好地“扩展”到需要做更多工作的更大的函数,在这些函数中,minBound使用哪种类型可能不太明显。这就导致我们 为类型变量启用词法范围。您可

假设我想定义一个函数,它使用为给定类型定义的一个常量。我试过:

minValue :: (Enum a,Bounded a) => a
minValue = minBound::a
但是函数定义不知道a是Enum类型,因为声明中指定了Enum类型。

两个合理的答案:

  • 删除内部类型签名

    minValue = minBound
    
    虽然这是可行的,但它不能很好地“扩展”到需要做更多工作的更大的函数,在这些函数中,
    minBound
    使用哪种类型可能不太明显。这就导致我们

  • 为类型变量启用词法范围。您可以使用
    forall
    关键字启动作用域;然后,该范围中的定义可以引用类型变量。因此:

    {-# LANGUAGE ScopedTypeVariables #-}
    minValue :: forall a. (Enum a, Bounded a) => a
    minValue = minBound :: a
    

  • 这里需要的是
    ScopedTypeVariables
    ,其中
    minValue
    中的
    a
    类型签名与定义中使用的
    a
    相同。然而,我怀疑您的用例不需要它。值
    minBound
    是多态的,当Haskell中的某些内容是多态的时,通常称为site-polymorphic。这意味着调用方确定类型,而不是定义。例如,您可以编写如下内容

    cycleBounded :: (Bounded a, Enum a, Eq a) => [a]
    cycleBounded
        = minBound
        : map (\n -> if n == maxBound then minBound else succ n)
              cycleBounded
    
    然后你可以做一些类似于
    cycleBounded::[Bool]
    的事情来得到与
    cycle[False,True]
    等价的东西。但是,如果您想在比较之前使用
    n
    上的
    fromnum
    maxBound
    来摆脱
    Eq
    约束,您会遇到一个问题,因为这样编译器就不知道
    maxBound
    要使用什么
    a
    ,上下文中没有说明它必须使用与
    n
    相同的类型,只是它是一个
    (枚举a,有界a)=>a
    。这将是
    ScopedTypeVariables
    的适当应用:

    {-# LANGUAGE ScopedTypeVariables #-}
    
    cycleBounded :: forall a. (Bounded a, Enum a, Eq a) => [a]
    cycleBounded
        = minBound
        : map (\n -> if fromEnum n == fromEnum (maxBound :: a) then minBound else succ n)
              cycleBounded
    
    虽然有一些技巧可以让这些类型在不需要
    ScopedTypeVariables
    的情况下实现统一,但大多数人可能会发现看到
    ScopedTypeVariables
    maxBound::a
    比任何东西都更容易理解。为了完整性,以下是如何使其统一:

    cycleBounded
        = minBound
        : map (\n -> let {m = maxBound;
                          x = [m, n] -- This forces `m` and `n` to have the same type
                         }
                     in if fromEnum n == fromEnum (head x)
                            then minBound
                            else succ n)
              cycleBounded
    
    在我看来,这是相当丑陋的