2016-03-08 89 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