Haskell实例签名
我是哈斯克尔的新手,所以请耐心点 假设我有这门课Haskell实例签名,haskell,Haskell,我是哈斯克尔的新手,所以请耐心点 假设我有这门课 class Indexable i where at :: i a p -> p -> a 现在让我们假设我想为这种数据类型实现typeclass: data Test a p = Test [a] 我尝试的是: instance Indexable Test where at (Test l) p = l `genericIndex` p 但是它没有编译,因为p需要是一个整数,但是据我所知,不可能将类型签名添加到实
class Indexable i where
at :: i a p -> p -> a
现在让我们假设我想为这种数据类型实现typeclass:
data Test a p = Test [a]
我尝试的是:
instance Indexable Test where
at (Test l) p = l `genericIndex` p
但是它没有编译,因为p
需要是一个整数,但是据我所知,不可能将类型签名添加到实例中。我尝试使用InstanceSigs,但失败了
有什么想法吗?您可以使用关联的类型族和约束类型:
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
,该类型
用于在处约束
的类型 实际上,您正在尝试做一些相当高级的事情。如果我了解您想要什么,您实际上需要一个多参数typeclass,因为您的类型参数“p”依赖于“I”:对于按整数索引的列表,您需要“p”是整数,但是对于按字符串索引的表,您需要它是“String”,或者至少是“Ord”的一个实例
这意味着这个类有两种类型,“i”和“p”,如果你知道“i”,那么“p”会自动跟随。因此,如果“i”是一个列表,“p”必须是Int,如果“i”是一个“映射字符串a”,那么“p”必须是“字符串”
这将[a]和Int的组合声明为可索引的实例
user2407038提供了一种使用“类型族”的替代方法,这是多参数类型类的一个更新更复杂的版本。这里是一个版本,您可以使用多参数类型类将索引类型添加到类中。
{-# 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
对于所有a.
;)
假设这是您的预期行为:
λ> let test = Test [1..5]
λ> test `at` 3
4
λ> test `at` 0
1
λ> test `at` (0 :: Int)
1
λ> test `at` (1 :: Integer)
2
只是为了好玩,这里有一个非常不同的解决方案,它不需要对类声明进行任何更改。(注意,这个答案只是为了好玩!我不主张保持你的类的原样;对我来说,这似乎是一个奇怪的类定义。)这里的想法是将证明责任从类实例推给构建类型Test p a
值的人;我们将要求构造这样一个值需要范围内的整数p
实例
所有这些代码保持完全相同(但启用了新扩展):
但是您的数据类型的声明只需稍微更改,就需要一个Integral p
实例:
data Test a p where
Test :: Integral p => [a] -> Test a p
也许族/约束类的内容有点重-为什么不从一个多参数类型类开始,添加索引类型呢?然后可以约束实例的索引类型
λ> let test = Test [1..5]
λ> test `at` 3
4
λ> test `at` 0
1
λ> test `at` (0 :: Int)
1
λ> test `at` (1 :: Integer)
2
{-# 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
data Test a p where
Test :: Integral p => [a] -> Test a p