2011-04-22 43 views
14

請參閱下面的代碼示例。它不會編譯。我曾想過也許是因爲它必須爲測試函數中的第一個參數設置一個類型。但這是沒有道理的,因爲如果我沒有模式匹配,所以它會編譯,我可以稱它爲MyObj11 5MyObj21 5這是兩種不同的類型。您可以在類型約束參數上設置匹配構造函數嗎?

那麼這是什麼限制,所以你不能在類型約束參數的構造函數上模式匹配?還是有一些你可以的機制?

class SomeClass a where toString :: a -> String 

instance SomeClass MyType1 where toString v = "MyType1" 
instance SomeClass MyType2 where toString v = "MyType2" 

data MyType1 = MyObj11 Int | MyObj12 Int Int 
data MyType2 = MyObj21 Int | MyObj22 Int Int 

test :: SomeClass a => a -> String 
test (MyObj11 x) = "11" 
test (MyObj12 x y) = "12" -- Error here if remove 3rd line: rigid type bound error 
test (MyObj22 x y) = "22" -- Error here about not match MyType1. 
+0

如果haskell的類是可關閉的 - 也就是說,您可以爲每個實現指定行爲,這可能是有意義的。但是Haskell類是開放的 - 當'instance SomeClass SomeoneElsesType whereString v =「mwahahahah」''時,如果給定'SomeoneElsesType'類型的值,'test'應該做些什麼?答案是處理這個問題的正確方法。 – rampion 2011-04-22 21:43:20

+3

這個問題對我來說似乎很明顯:它會做任何模式匹配說它應該。如果沒有模式匹配,就會像其他任何這樣的情況一樣出現這樣的錯誤。我沒有看到區別。 – mentics 2011-04-22 22:44:37

回答

19

它是什麼,一個類型的類約束參數限制在構造函數,所以你不能模式匹配?

當您在顯式構造函數上進行模式匹配時,您將提交給特定的數據類型表示。這種數據類型不是在類的所有實例之間共享的,所以不可能用這種方式編寫適用於所有實例的函數。

相反,你需要不同的行爲,你想與每個實例相關聯,就像這樣:現在

class C a where 
    toString :: a -> String 
    draw  :: a -> String 

instance C MyType1 where 
    toString v = "MyType1" 

    draw (MyObj11 x) = "11" 
    draw (MyObj12 x y) = "12" 

instance C MyType2 where 
    toString v = "MyType2" 

    draw (MyObj22 x y) = "22" 

data MyType1 = MyObj11 Int | MyObj12 Int Int 
data MyType2 = MyObj21 Int | MyObj22 Int Int 

test :: C a => a -> String 
test x = draw x 

你原來test功能的分支機構分佈在實例之中。

一些替代技巧涉及使用class-associated data types(向編譯器證明數據類型在所有實例之間共享)或view patterns(它允許您概括模式匹配)。


查看模式

我們可以使用視圖模式來清理模式匹配和類型的類的實例,有點之間的連接,讓我們通過模式上的共享匹配近似的圖案跨實例匹配類型。

下面是一個例子,我們寫了一個函數,有兩種情況,讓我們對類中的任何事物進行模式匹配。

{-# LANGUAGE ViewPatterns #-} 

class C a where 
    view  :: a -> View 

data View = One Int 
      | Two Int Int 

data MyType1 = MyObj11 Int | MyObj12 Int Int 

instance C MyType1 where 
    view (MyObj11 n) = One n 
    view (MyObj12 n m) = Two n m 

data MyType2 = MyObj21 Int | MyObj22 Int Int 

instance C MyType2 where 
    view (MyObj21 n) = One n 
    view (MyObj22 n m) = Two n m 

test :: C a => a -> String 
test (view -> One n) = "One " ++ show n 
test (view -> Two n m) = "Two " ++ show n ++ show m 

注意->語法如何讓我們在每一個實例回調到合適的view功能,查找每類自定義數據類型的編碼,以模式匹配就可以了。

設計的挑戰是要拿出捕獲所有的行爲變種你感興趣的視圖類型。

在你原來的問題,你想每一個構造有不同的行爲,所以實際上沒有使用視圖類型的原因(在每個實例中直接調度到該行爲已經足夠好)。

+0

好吧,看起來這個語句是爲什麼的開始:「當你在一個顯式的構造函數上進行模式匹配時,你會提交一個特定的數據類型表示。」好的,那爲什麼呢?爲什麼模式匹配會導致此承諾在該點輸入? – mentics 2011-04-22 22:46:48

+1

模式匹配解構*具體數據類型*。你選擇一個特定的類型,並查看它的構造函數。這意味着您的代碼不能再適用於所有類型。現在,您可以將我的上面的代碼翻譯成您可以同時對多種類型進行模式匹配的語法,但這不是Haskell的工作原理。不過這是一個有趣的想法。 – 2011-04-22 22:50:09

+0

我認爲這個評論問題是,爲什麼Haskell不這樣工作?爲什麼這種語言的這種特徵是以這種限制性的方式設計的? – 2011-04-22 23:05:12

相關問題