2017-02-22 77 views
0

當我嘗試執行使用類型參數調用數據的此函數時,出現錯誤。Haskell中的類型參數問題

data Car a b c = Car { company :: a 
       , model :: b 
       , year :: c 
       } deriving (Show) 

myCar :: Car -> String 
myCar (Car {company = c, model = m, year = y}) = "This " ++ C++ " was made in " ++ m ++ " " ++ show (y) 

我收到此錯誤

* Expecting three more arguments to `Car' 
    Expected a type, but `Car' has kind `* -> * -> * -> *' 
* In the type signature: 
    myCar :: Car -> String 

它的工作原理,如果我提前使用類型的參數,如下面

data Car = Car { company :: String 
       , model :: String 
       , year :: Int 
       } deriving (Show) 

感謝。

+1

「我得到這個錯誤」正確的是,因爲寫入的代碼沒有任何意義。 「如果我不使用下面的類型參數,它就可以工作」也完全可以,這絕對是正確的。所以有什麼問題? –

+0

道歉,我已經更新了這個問題,它在我嘗試使用數據類型時起作用,但在嘗試使用類型參數時不起作用。 – Srinivas

+2

再次,問題是什麼?你期望'公司'或'模型'不是'字符串','年份'不是'Int'的東西嗎?爲什麼? –

回答

3

您定義的類型爲Car a b c,而不是Car。你以後試圖使用的僅僅是Car,編譯器會警告你(關於你有點神祕)消息Expecting three more arguments to 'Car'。實際上僅僅期望Car作爲一種神奇的工作是沒有意義的,這些領域會是什麼?一旦你指定了a,bc是什麼,它纔開始有意義。所以Car可以用來構造一個類型(比如Car String String String),因此它被稱爲類型的構造函數。爲了區分這些並且爲價值水平結構作類比,Haskell使用種類非常喜歡它使用類型來將個體值分組。

Car是種類* -> * -> * -> *意味着它需要3種類型才能生成混凝土第四種類型。

要使用編譯器魔術自動派生Show您需要確保組成部分也實例化Show。如果沒有這個,編譯器不能期望神奇地想出一種方法來以任何合理的方式將任意類型轉換爲字符串(正如您期望的從show)。您可以使用約束實現這一但據我所知,您可以使用語言擴展GADTs

{-# LANGUAGE GADTs #-} 
data Car a b c where 
    Car :: (Show a, Show b, Show c) 
     => { company :: a, model :: b, year :: c } 
     -> Car a b c 

時只添加,但你仍然不能直接使用deriving Show,因爲這似乎工作,只有當類型Car a b c適用於任何a,b,c,在此情況並非如此。至少不要與ghc-7.10。這是做什麼的,它只是在構建汽車時不允許a,b,c的錯誤選擇。沒有Show實例的類型的一個示例是函數類型,並且通過請求Show a, Show b, Show c來禁止它是有意義的。不幸的是,您需要添加

instance (Show a, Show b, Show c) => Show (Car a b c) where 
    show (Car a b c) = "Car " ++ show a ++ " " ++ show b ++ " " ++ show c 
3

你有兩個問題。本身並不是一種類型,而是一種類型的構造函數。此外,您還需要爲類型參數添加Show約束,以便使String無法使用。

試試這個:

myCar :: (Show c, Show m, Show y) => Car c m y -> String 
myCar (Car c m y) = "This " ++ (show c) ++ " was made in " ++ (show m) ++ " " ++ (show y) 
2

在類型簽名myCar :: Car -> String,你忘了類型參數添加到Car類型。既然你指定Car類型採取3個類型參數:

data Car a b c = ... 

在每一個在使用這種類型的點,你必須給它3個類型參數;您可以將Car a b c視爲一種類型級別的函數,在獲得一種類型*之前,您必須提供3種類型的函數。你得到的錯誤說類型Car是種類* -> * -> * -> *意味着Car類型是「更高親密度」,這是一種奇怪的方式,表示類型需要像一個函數一樣應用於一種或多種類型一種類型*(以0類型作爲參數的類型)。在這種情況下,您需要將類型構造函數應用於其他3種類型,然後才能成爲類型*

因此,在正確的方向邁出的一步是改變類型簽名是這樣的:

myCar :: Car String String Int -> String 

這應該解決您的問題。