2011-09-03 80 views
3

的獲得I型有型哈斯克爾代數參數

class IntegerAsType a where 
    value :: a -> Integer 

data T5 
instance IntegerAsType T5 where value _ = 5 

newtype (IntegerAsType q) => Zq q = Zq Integer deriving (Eq) 

newtype (Num a, IntegerAsType n) => PolyRing a n = PolyRing [a] 

我試圖做的PolyRing型一個不錯的「秀」。特別是,我想讓「秀」打印出型號'a'。是否有一個函數返回代數參數的類型(類型爲'show')?

我試圖做的另一種方式是使用模式匹配,但我遇到了內置類型和代數類型的問題。

我想爲Integer,Int和Zq q中的每一個獲得不同的結果。 (例如玩具:)

test :: (Num a, IntegerAsType q) => a -> a 
(Int x) = x+1 
(Integer x) = x+2 
(Zq x) = x+3 

這裏有至少兩個不同的問題。

1)Int和Integer不是'Int'和'Integer'類型的數據構造函數。是否有這些類型的數據構造函數/如何模式匹配?

2)雖然在我的代碼中沒有顯示,但Zq是Num的一個實例。我得到的問題是:

Ambiguous constraint `IntegerAsType q' 
At least one of the forall'd type variables mentioned by the constraint 
must be reachable from the type after the '=>' 
In the type signature for `test': 
test :: (Num a, IntegerAsType q) => a -> a 

我有點看到它爲什麼抱怨,但我不知道如何解決這個問題。

感謝

編輯: 的什麼,我試圖與測試功能做一個更好的例子:

test :: (Num a) => a -> a 
test (Integer x) = x+2 
test (Int x) = x+1 
test (Zq x) = x 

即使我們忽略了一個事實,我不能構建整數和INTS這種方式(仍想知道如何!),這種「測試」並沒有編譯,因爲:

Could not deduce (a ~ Zq t0) from the context (Num a) 

我的下一次嘗試在此功能與類型簽名:

test :: (Num a, IntegerAsType q) => a -> a 

從而導致新的錯誤

Ambiguous constraint `IntegerAsType q' 
At least one of the forall'd type variables mentioned by the constraint 
must be reachable from the type after the '=>' 

我希望這是我的問題更清楚一點....

回答

4

我不知道你在與test功能驅動是什麼,但如果你喜歡,你可以做這樣的事情:

{-# LANGUAGE ScopedTypeVariables #-} 
class NamedType a where 
    name :: a -> String 
instance NamedType Int where 
    name _ = "Int" 
instance NamedType Integer where 
    name _ = "Integer" 
instance NamedType q => NamedType (Zq q) where 
    name _ = "Zq (" ++ name (undefined :: q) ++ ")" 

我不會做我的堆棧溢出的責任,如果我做不要跟着這個答案提出警告:你要求的是非常非常奇怪的。你可能正在以非常自由的方式做一些事情,並且將以整個方式與語言作鬥爭。我強烈建議您的下一個問題是一個更廣泛的設計問題,以便我們可以幫助您指導一個更習慣的解決方案。

編輯

還有一個半到你的問題,即如何寫test功能「模式匹配」的輸入端,查看它是否是一個Int,一個Integer,一個Zq類型等。你提供這個暗示的代碼片段:

test :: (Num a) => a -> a 
test (Integer x) = x+2 
test (Int x) = x+1 
test (Zq x) = x 

有幾件事要澄清在這裏。

Haskell有三個級別的對象:值級別,類型級別和種類級別。價值級別的東西的一些示例包括"Hello, world!",42,函數\a -> afix (\xs -> 0:1:zipWith (+) xs (tail xs))。類型級別的東西的一些示例包括Bool,Int,Maybe,Maybe IntMonad m => m()。類似的東西的一些例子包括*(* -> *) -> *

水平是有序的;值級別對象按類型級別對象進行分類,並且類型級別對象按類別級別對象進行分類。我們使用::來編寫分類關係,例如,32 :: Int"Hello, world!" :: [Char]。 (那種水平是不是這個討論太有趣了,但*分類類型和箭頭種分類型構造。例如,Int :: *[Int] :: *,但[] :: * -> *)。現在

,哈斯克爾的最基本屬性之一每個級別都是完全隔離的。你永遠不會在類型中看到像"Hello, world!"這樣的字符串;同樣,價值水平的對象不會傳遞或操作類型。而且,對於值和類型,還有單獨的名稱空間。就拿Maybe的例子:

data Maybe a = Nothing | Just a 

這個聲明在類型級別創建了一個新的名字Maybe :: * -> *,和兩個新的名字Nothing :: Maybe aJust :: a -> Maybe a在價值層面。一種常見模式是爲類型構造函數和值構造函數使用相同的名稱,如果只有一個;例如,你可能會看到

newtype Wrapped a = Wrapped a 

其在類型級別聲明瞭一個新的名字Wrapped :: * -> *,同時在價值層面宣佈一個明確的名稱Wrapped :: a -> Wrapped a。一些特別常見的(和混亂的例子)包括(),這既是一個值級對象(的()型)和一種類型的級對象(的種類*),和[],它是(的類型兩者的值級對象[a])和類型級別的對象(種類* -> *)。請注意,價值級別和類型級別的對象在源代碼中拼寫相同的事實只是一個巧合!如果你想混淆你的讀者,你可以寫得很好

newtype Huey a = Louie a 
newtype Louie a = Dewey a 
newtype Dewey a = Huey a 

這三個聲明根本沒有關係!

現在,我們終於可以解決上面test出錯的問題了:IntegerInt不是值構造函數,所以它們不能在模式中使用。請記住 - 值級別和類型級別是孤立的,因此您不能將類型名稱放入值定義中!現在,你可能希望你寫test'代替:

test' :: Num a => a -> a 
test' (x :: Integer) = x + 2 
test' (x :: Int) = x + 1 
test' (Zq x :: Zq a) = x 

...但很可惜,它不完全是這樣工作的。價值層面的東西不允許依賴於類型層次的東西。你可以做的是寫在每個IntInteger,並Zq a類型的單獨功能:

testInteger :: Integer -> Integer 
testInteger x = x + 2 

testInt :: Int -> Int 
testInt x = x + 1 

testZq :: Num a => Zq a -> Zq a 
testZq (Zq x) = Zq x 

然後我們就可以調用這些功能的合適的一個,當我們想要做一個測試。由於我們使用的是靜態類型語言,因此這些函數中的其中一個函數將適用於任何特定的變量。現在

,這是一個有點麻煩記住調用正確的函數,所以哈斯克爾提供了一個輕微的便利:可以讓編譯器選擇在編譯的時候,這些功能爲你一個。這種機制是類背後的重要理念。它看起來像這樣:

class Testable a where test :: a -> a 
instance Testable Integer where test = testInteger 
instance Testable Int where test = testInt 
instance Num a => Testable (Zq a) where test = testZq 

現在,看起來好像有叫test一個單一的功能,可以處理任何的IntInteger,或者數字Zq的 - 但實際上有三個功能,並且編譯器是透明地爲你選擇一個。這是一個重要的見解。該類型的test

test :: Testable a => a -> a 

...看起來乍一看就像是一個函數,它可能是任何Testable類型的值。但實際上,這是一種功能,可以專門用於任何Testable類型 - 然後只有接受該類型的值!這種差異解釋了原始test函數不起作用的另一個原因。您不能在不同類型的變量中使用多個模式,因爲該函數一次只能處理一種類型的變量。

NamedTypeTestable背後的想法以上可概括一個位;如果你這樣做,你會得到上面hammar建議的Typeable類。

我想現在我已經天馬行空綽綽有餘,並且很可能混淆更多的東西比我清楚,但給我留下了評論說法,其中部分都不清楚,我會盡我所能。

+0

hammar回答了我的問題的第一部分。不過,我仍然對如何進行模式匹配感興趣。你可以在Int和Integer模式匹配嗎? – crockeea

+0

我欣賞這個警告,並意識到我可能正在挖一個洞... 讓我試着給一個函數的更好的例子,我可能實際上需要我所要求的: test::(Num a)=> a - > a test(Int x)= x + 2 test (Zq x)的類型參數,所以我可以修改,如果我需要。更重要的是,它不會編譯(即使我拿出不可構造的Int和Integer行)。隨着類型簽名給定的,我得到的錯誤:從上下文(民一) 無法推斷(一〜ZQ T0) – crockeea

+0

似乎有在這裏是一些誤解關於類型。給我幾分鐘,我會更新我的答案,討論我能做些什麼。 –

2

Is there a function that returns the type of an algebraic parameter (a 'show' for types)?

我認爲Data.Typeable可能是你在找什麼對於。

Prelude> :m + Data.Typeable 
Prelude Data.Typeable> typeOf (1 :: Int) 
Int 
Prelude Data.Typeable> typeOf (1 :: Integer) 
Integer 

注意,這不會對任何類型工作,只是那些有Typeable實例。 使用擴展DeriveDataTypeable,可以讓編譯器自動得出這些爲自己的類型:

{-# LANGUAGE DeriveDataTypeable #-} 

import Data.Typeable 

data Foo = Bar 
    deriving Typeable 
*Main> typeOf Bar 
Main.Foo 

我不太明白你想在下半年做什麼你問題,但希望這應該有一些幫助。