如何获得函数类型定义中声明的Enum类型的最小值?

时间:2015-03-28 01:50:09

标签: haskell

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

minValue :: (Enum a,Bounded a) => a
minValue = minBound::a

但是函数定义不知道a是Enum类型,因为它在声明中指定。

2 个答案:

答案 0 :(得分:7)

两个合理的答案:

  1. 删除内部类型签名。

    minValue = minBound
    

    虽然这有效,但它没有"规模"以及需要做更多事情的大型函数,对于minBound使用哪种类型可能不那么明显。这导致我们

  2. 打开类型变量的词法作用域。您可以使用forall关键字开始范围;然后该范围内的定义可以引用类型变量。因此:

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

答案 1 :(得分:1)

您想要的是ScopedTypeVariables,其中a的{​​{1}}类型签名与定义中使用的minValue相同。但是,我怀疑你的用例不需要它。值a是多态的,当Haskell中的某些内容是多态的时,它通常是调用站点多态。这意味着调用者确定类型,而不是定义。例如,您可以编写类似

的内容
minBound

然后你可以做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]Eq上的fromEnum来摆脱n约束,则会遇到问题,因为编译器不会知道maxBound要用于Bounded a => a,在上下文中没有任何内容表明它必须使用与maxBound相同的类型,只是它是n。这将是(Enum a, Bounded 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 的情况下统一这些类型,但大多数人可能会发现ScopedTypeVariablesScopedTypeVariables比任何事情都更容易理解。为了完整起见,您可以通过以下方式将其统一起来:

maxBound :: a

在我看来,这是非常难看的。