我是Haskell的新手,所以请耐心等待。
假设我有这个课程
class Indexable i where
at :: i a p -> p -> a
现在假设我想为这种数据类型实现该类型类:
data Test a p = Test [a]
我尝试的是:
instance Indexable Test where
at (Test l) p = l `genericIndex` p
然而它没有编译,因为p
需要是一个Integral,但据我所知,将类型签名添加到实例是不可能的。我尝试使用InstanceSigs,但失败了。
有什么想法吗?
答案 0 :(得分:4)
这是一个使用MultiParamTypeClasses
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
module Index where
import Data.List (genericIndex)
class Indexable i f where
at :: forall a . f a -> i -> a
data Test a = Test [a]
instance Integral i => Indexable i Test where
at (Test as) i = as `genericIndex` i
这里我需要FlexibleInstances
,因为实例的声明方式和RankNTypes
的{{1}};)
假设这是您的预期行为:
forall a .
答案 1 :(得分:2)
你实际上是在尝试做一些相当先进的事情。如果我理解你想要的东西,你实际上需要一个多参数类型类,因为你的类型参数“p”取决于“i”:对于一个由整数索引的列表,你需要“p”为整数,但是对于一个由字符串索引的表你需要它是“字符串”,或至少是“奥德”的一个实例。
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-} -- Enable the language extensions.
class Indexable i p | i -> p where
at :: i a -> p -> a
这表示该类有两种类型,“i”和“p”,如果你知道“i”,那么“p”会自动跟随。因此,如果“i”是列表,则“p”必须是Int,如果“i”是“Map String a”,则“p”必须是“String”。
instance Indexable [a] Int where
at = (!!)
这声明[a]和Int的组合是Indexable的实例。
user2407038提供了一种使用“类型族”的替代方法,这是多参数类型类的更新和复杂版本。
答案 2 :(得分:2)
只是为了好玩,这是一个非常不同的解决方案,不需要对您的课程声明进行任何更改。 (注意:这个答案仅仅是为了好玩!我不主张保持你的课程原样;这对我来说似乎是一个奇怪的课程定义。)这里的想法是将证明的负担从课堂实例转移到构建一个人的人身上。类型Test p a
的值;我们将要求构造这样的值将需要范围内的Integral p
实例。
所有这些代码保持完全相同(但启用了新的扩展名):
{-# LANGUAGE GADTs #-}
import Data.List
class Indexable i where
at :: i a p -> p -> a
instance Indexable Test where
at (Test l) p = l `genericIndex` p
但是,您的数据类型声明只会稍微改变,以要求Integral p
实例:
data Test a p where
Test :: Integral p => [a] -> Test a p
答案 3 :(得分:1)
您可以使用关联的类型系列和约束种类:
import GHC.Exts(Constraint)
class Indexable i where
type IndexableCtr i :: * -> Constraint
at :: IndexableCtr i p => i a p -> p -> a
instance Indexable Test where
type IndexableCtr Test = Integral
at (Test l) p = l `genericIndex` p
这定义了具有关联类型Indexable
的类IndexableCtr
用于约束at
的类型。