2011-09-30 85 views
5

我有一個多項式哈斯克爾「僞仿」

data Poly a = Poly [a] 

我希望能夠做一些像fmap (take 3) polynomial但我不能,因爲Poly是不是真的,該f我使用的是仿函數在fmap只能是[a] -> [b]類型,而不是a -> b

有沒有一種成語或方式可以表達我想要的東西?


編輯:這裏是一個函數,我想要做什麼

myMap :: ([a] ->[b]) -> P a -> P b 
myMap f (P x) = P (f x) 

用法:

*Main> myMap (take 3) (P [1..]) 
P [1,2,3] 

您可以從類型的簽名,它是幾乎 FMAP看,但不相當。我顯然有能力編寫myMap的代碼,但我只想知道是否有另一個我應該使用的習慣用法。

+0

你想要'fmap(take 3)polynomial'做什麼?我根本沒有意義。 - 'polynomial'只是一個多項式:: Poly CoeffType'' polynomial = Poly [a 1,a 2 ..]'? – leftaroundabout

+0

@leftaroundabout:我給出了一些示例代碼。 – Xodarap

+0

由於這不是一個真正的規範操作(類型類應該如何知道它是一個列表,而不是一個數組),我根本不會讓它成爲任何實例。我也不會稱之爲「some-'map'」而是「coeffsTransform」或類似的東西。 – leftaroundabout

回答

10

由於您允許將任何函數應用於係數列表,因此您的數據類型僅用於兩個目的。

  • 由於Poly [a]不同於[a],因此可以獲得額外的安全性。
  • 您可以定義不同的實例。

如果你不需要其中任何一個,你可以使用一個類型別名。

type Poly a = [a] 

現在你可以直接應用任何列表功能。

另一方面,如果您想要一個不同的類型,您可能會發現the newtype package有用。例如,給定這個例子。

instance Newtype (Poly a) [a] where 
    pack = Poly 
    unpack (Poly x) = x 

您現在可以寫東西像

foo :: Poly a -> Poly a 
foo = over Poly (take 3) 

儘管這可能是矯枉過正,如果你的myMap足以滿足您的目的。


這一切不談,我認爲,暴露你的數據類型的表示以這樣的方式可能不是擺在首位是一個好主意,因爲它可以讓你的代碼的其餘部分密切依賴於這種表示。

這使得以後難以更改爲其他表示方式。例如,您可能希望更改爲稀疏表示像

data Poly a = Poly [(a, Int)] 

其中Int是長期的力量。我建議你考慮一下你想要暴露什麼樣的操作,並限制自己。例如,可能有一個Functor實例在每個元素的基礎上工作。

instance Functor Poly where 
    fmap f (Poly x) = Poly $ map f x 

現在,對稀疏表示的更改會使客戶端代碼保持不變。只有實例(以及少數依賴於表示的其他函數)將不得不改變。

instance Functor Poly where 
    fmap f (Poly x) = Poly $ map (first f) x 
+0

+1偉大的建議! – luqui

+0

謝謝,它看起來像[數字前奏](http://hackage.haskell.org/packages/archive/numeric-prelude/0.2.2.1/doc/html/src/MathObj-Polynomial.html#T)使用fmap你指定的方式。 – Xodarap

2

這並不工作,但我認爲這是足夠有趣反正分享到:

{-#LANGUAGE GADTs #-} 

data Poly a where 
    Poly :: [b] -> Poly [b] 

我們現在有一個型Poly這是參數上a,但有效a必須是一個列表:

~% ghci Poly.hs 
GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help 
Loading package base ... linking ... done. 
[1 of 1] Compiling Main    (Poly.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> :k Poly 
Poly :: * -> * 
*Main> :t Poly 
Poly :: [b] -> Poly [b] 
*Main> case Poly [1,2,3] of _ -> 0 
0 
*Main> case Poly 4 of _ -> 0 

<interactive>:1:10: 
    No instance for (Num [b]) 
     arising from the literal `4' at <interactive>:1:10 
    Possible fix: add an instance declaration for (Num [b]) 
    In the first argument of `Poly', namely `4' 
    In the scrutinee of a case expression: Poly 4 
    In the expression: case Poly 4 of _ -> 0 
*Main> case Poly True of _ -> 0 

<interactive>:1:10: 
    Couldn't match expected type `[b]' against inferred type `Bool' 
    In the first argument of `Poly', namely `True' 
    In the scrutinee of a case expression: Poly True 
    In the expression: case Poly True of _ -> 0 

現在我們可以試着寫的Functor的實例,該類型:

instance Functor Poly where 
    fmap f (Poly x) = Poly (f x) 

Couldn't match expected type `[b1]' against inferred type `b2' 
    `b2' is a rigid type variable bound by 
     the type signature for `fmap' at <no location info> 
In the first argument of `Poly', namely `(f x)' 
In the expression: Poly (f x) 
In the definition of `fmap': fmap f (Poly x) = Poly (f x) 

這不起作用。有趣的是,我們甚至不能真正寫myMap

polymap f (Poly x) = Poly (f x) 

如果我們試試這個,我們得到

GADT pattern match in non-rigid context for `Poly' 
    Tell GHC HQ if you'd like this to unify the context 
In the pattern: Poly x 
In the definition of `polymap': polymap f (Poly x) = Poly (f x) 

當然,我們可以用一個類型標註修復:

polymap :: ([a] -> [b]) -> Poly [a] -> Poly [b] 

但沒有它,這與fmap有什麼相似的問題。 Functor只是沒有任何地方可以擺脫這個額外的「我保證總是使用列表」的內容,而且它確實不能。例如,您總是可以說undefined :: Poly Int。總之,我不認爲有這樣一個成語可以表達這一點(實際上,有人可能會用足夠的ghc擴展魔術來做到這一點)。當然不是現有的。