我有一个Foo a
类型,并且需要一个需要EnumFoo a
的类型instance Enum (Foo a)
。你怎么声明这种类型?
假设我们像这样声明Foo
:
type Foo a = Maybe a
可以有Foo Int
,Foo String
等任何内容
现在我在Enum
上声明Foo Int
的实例:
instance Enum (Foo Int) where
...
可能有一些其他Foo
具有Enum
这样的实例。我们称这些类型为EnumFoo a
。你是如何表达的?
这不起作用,但我想做的是:
type (Enum (Foo a)) => EnumFoo a = Foo a
我不确定它叫什么,所以标题应该毫无意义。
答案 0 :(得分:6)
作为bheklilr suggested,听起来你想要的是一个GADT:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}
module Foo where
data Foo a = Foo (Maybe a)
data EnumFoo a where
EnumFoo :: Enum (Foo a) => Foo a -> EnumFoo a
制作EnumFoo a
(undefined
除外)的唯一方法是应用EnumFoo
构造函数,该构造函数强加Enum (Foo a)
上下文。然后你可以写一些像
blah :: EnumFoo a -> [EnumFoo a]
blah (EnumFoo foo) = map EnumFoo [toEnum 1 .. foo]
请注意,您需要FlexibleContexts
扩展名,因为标准Haskell不允许使用Enum (Foo a)
等上下文;它只允许简单的事情,如Enum Foo
或Enum a
。
bheklilr还提到了一个较旧的声明表单,在标准data
声明中加上了一个上下文。虽然这种形式是标准的Haskell(它在Haskell 98和Haskell 2010报告中),但它被广泛认为是错误的,GHC甚至不允许它没有LANGUAGE
编译指示。问题是虽然它限制了允许的类型变量,但它并不能让你使用这些约束。