假设我想定义一个使用为给定类型定义的常量之一的函数。我试过了:
minValue :: (Enum a,Bounded a) => a
minValue = minBound::a
但是函数定义不知道a是Enum类型,因为它在声明中指定。
答案 0 :(得分:7)
两个合理的答案:
删除内部类型签名。
minValue = minBound
虽然这有效,但它没有"规模"以及需要做更多事情的大型函数,对于minBound
使用哪种类型可能不那么明显。这导致我们
打开类型变量的词法作用域。您可以使用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
的情况下统一这些类型,但大多数人可能会发现ScopedTypeVariables
和ScopedTypeVariables
比任何事情都更容易理解。为了完整起见,您可以通过以下方式将其统一起来:
maxBound :: a
在我看来,这是非常难看的。