2016-03-08 92 views
1

我是Haskell中的一名完全新手,请耐心等待。Haskell实例签名

比方说,我有这个类

class Indexable i where 
    at :: i a p -> p -> a 

现在让我们说,我想implent该类型类的数据类型为:

data Test a p = Test [a] 

我想的是:

instance Indexable Test where 
    at (Test l) p = l `genericIndex` p 

但它没有编译,因为p需要是一个积分,但据我所知,它是不可能的,添加为实例键入签名。我试图使用InstanceSigs,但失败了。

任何想法?

+0

也许家庭/约束类的东西有点沉重 - 你为什么不开始使用多参数类型类型并添加索引类型?那么你可以约束你的实例的* index *类型 – Carsten

回答

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与 是用来约束at类型的相关类型IndexableCtr

2

你实际上正在尝试做一些相当先进的事情。如果我明白你想要什么,你实际上需要一个多参数类型类型,因为你的类型参数“p”取决于“i”:对于一个用整数索引的列表,你需要“p”是整数,但对于一个由字符串索引的表你需要它是“字符串”,或者至少是“Ord”的一个实例。

{-# LANGUAGE FunctionalDependencies #-} 
{-# LANGUAGE MultiParamTypeClasses #-} -- Enable the language extensions. 

class Indexable i p | i -> p where 
    at :: i a -> p -> a 

这是说的类是两种类型,“i”和“P”,如果你知道“我”,然后“P”自动跟随。所以如果“我”是一个列表,“p”必须是Int,如果“i”是“Map String a”,那么“p”必须是“String”。

instance Indexable [a] Int where 
    at = (!!) 

这声明[a]和Int的组合是一个Indexable的实例。

user2407038提供了一种使用“类型族”的替代方法,该类型族是多参数类型类的更新和复杂版本。

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的,因为实例声明的方式RankNTypesforall a .;)

假设这是您预期的行为:

λ> let test = Test [1..5] 
λ> test `at` 3 
4 
λ> test `at` 0 
1 
λ> test `at` (0 :: Int) 
1 
λ> test `at` (1 :: Integer) 
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