2011-01-26 73 views
9

是否有方法爲值構造函數的參數定義類約束?在值構造函數中指定類約束

事情是這樣的:

data Point2D = (Num a) => Point a a 

使點可以採用任何參數,只要他們屬於民課嗎?

+0

一般來說,最好將您的類型約束放在實際需要的地方。這不是數據類型,而是需要Num類型的方法,所以應該在那裏聲明。類型系統將負責其餘部分。 – amccausl 2011-01-27 06:45:58

回答

11

您可以使用ExistentialQuantificationGADTs,但都不會做你想要的。您將永遠無法使用兩個Point2D值進行算術運算。所有你知道的內容是,他們是一些 Num的實例。您正在告訴編譯器放棄關於它們的所有其他信息。這意味着您要告訴編譯器放棄任何可能具有的信息,即一對Point2D值包含相同的類型。如果沒有這些信息,您將無法對兩個Point2D的值進行任何算術運算。

這幾乎肯定不是你想要的。例如,你不能寫一個distance函數。對於這種有限的類型你有什麼可能的用途?關於你所能做的所有事情是把他們的內容轉換爲String

編輯:

我想我明白你在做什麼。你只是想確保Point2D中的所有內容都是一個數字。我不認爲你真的想要類型擦除。

在這種情況下,我會去與GADT版本,其中一個非常重要的變化:

{-# LANGUAGE GADTs #-} 
data Point2D a where 
    Point :: (Num a) => a -> a -> Point2D a 

這樣做的最終結果是,你只能使用Point構造具有相同的兩個值Num的實例,但不會丟失類型。此外,由於使用了GADTs,構造函數Point上的模式匹配爲您恢復了Num上下文,這基本上就是您期望的。

但我認爲這裏最重要的不是丟棄內容的類型。這樣做使得該類型基本上不可能合作。

+0

爲數據成員恢復實例上下文似乎只在數據類型(使用`(Point a b)`或使用記錄字段名稱`Point {x = a,y = b}`)進行模式匹配時才起作用。但有什麼辦法可以讓這個字段訪問功能?也就是說,當用像`(x p)`這樣的表達式來訪問`Point`` p`時。 – Lii 2016-06-09 14:14:49

4

是,但您必須認識到約束的含義與通常的泛型不同。

通常情況下,像仿製藥type Foo a = (a, a)意味着

爲各類aFoo a由兩a

然而,在你的榜樣,需要短語是不同的:

對於索姆e型aPoint2D由兩a

一個類型aPoint2D

因此,通用的類型不是通用(適用於所有類型...),但是存在(它存在某種類型...)。在GHC,我們可以通過extenstion

{-# ExistentialQuantification #-} 

在本article on the topic描述允許這樣。您的代碼,畢竟是

data Point2D = forall a . Num a => Point a a 
2

當然!

這應該做你想要什麼:

{-# LANGUAGE GADTs #-} 

data Point2D a where 
    Point :: Num a => a -> a -> Point2D a 

p :: Num a => a -> a -> Point2D a 
p = Point 

sumP :: Point2D a -> Point2D a -> a 
sumP (Point a b) (Point c d) = a + b + c + d 

您還可以使用existensials,但你不能做後它的模式匹配的數據什麼。