Haskell实例签名

时间:2016-03-08 18:10:49

标签: haskell

我是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,但失败了。

有什么想法吗?

4 个答案:

答案 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的类型。