Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell实例签名_Haskell - Fatal编程技术网

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