你所要求的是不可能的(至少很難),儘管起初很難看清楚。
此處分析的適當工具是編譯時/運行時區別出現在您的代碼中。具體來說,假設我們有一個函數maps
,這樣maps 3 f
將f
映射到列表的第三層。它的類型是什麼?好了,我們可以把它們寫出來
maps 1 :: (a -> b) -> [a] -> [b]
maps 2 :: (a -> b) -> [[a]] -> [[b]]
maps 3 :: (a -> b) -> [[[a]]] -> [[[b]]]
...
這可能已經看起來很奇怪,但如果還沒有那麼認真地注意到什麼是怎麼回事:終極型maps n f
取決於值n
,這隻能在運行時才能知道。
因爲我們要進行類型檢查在編譯時和maps
存在的東西就意味着我們不能知道maps n
類型不知道那我們就沉沒的n
運行值。這樣的功能maps
不能存在。
無論如何。在實踐中,我們當然可以解決這種情況。但是,像往常一樣,當出現類型錯誤時,我們首先必須更清楚我們要實現的目標。我們想將map
操作擴展爲維數組。只要我們在編譯時(再次,將是一個有點挑戰性的逃脫),那麼我們也可以被明確這個想法
newtype TwoD a = TwoD { getLists2d :: [[a]] }
newtype ThreeD a = ThreeD { getLists3d :: [[[a]]] }
newtype FourD a = FourD { getLists4d :: [[[[a]]]] }
-- etc...
現在這些每一個有固定n
map
的自然延伸。事實上,這種想法多種類型是的「map
pable」是Functor
類型類的完全的直覺,所以我們可以實例它們都作爲Functor
小號
instance Functor TwoD where fmap f (TwoD lists) = TwoD ((map . map) f lists)
instance Functor ThreeD where fmap f (ThreeD lists) = ThreeD ((map . map . map) f lists)
-- etc...
其實,這是這樣一個自然的想法是GHC實現一個擴展,它將爲我們派生這些Functor
實例。
{-# LANGUAGE DeriveFunctor #-}
newtype TwoD a = TwoD { getLists2d :: [[a]] } deriving Functor
newtype ThreeD a = ThreeD { getLists3d :: [[[a]]] } deriving Functor
newtype FourD a = FourD { getLists4d :: [[[[a]]]] } deriving Functor
-- etc...
現在fmap
可以在我們的任何n
維數組類型的使用很自然。
另一種可能的解釋是,我們想不表示n
維數組,而是一個「玫瑰樹」。不同的是,在n
維數組中,「索引序列」每的值爲n
元素長。例如,左上角的值在[0,0,0]
的ThreeD
索引。在Rose
樹中,我們有列表的混合,並且不是每個值都處於相同的深度。這意味着我們不再像對[a]
與[[[[a]]]]
這樣的類型做類似列表深度的靜態保證,但它也意味着所有深度信息現在都在運行時發生。
哪個是我們想要的地方。我們先定義Rose
。
data Rose a = Rose [Rose a] | L a deriving Functor -- Functor for free!
我們也可以生產的Rose Char
樣本值,使之更加清楚如何Rose
作品。
Rose [Rose [L 'f', L 'o', L 'o', Rose [L 'x', L 'y', L 'z']], L 'b', L 'a', L 'r']
我喜歡把Rose
爲類似於「口齒不清」式列表,即任意嵌套的樹木。
(('f' 'o' 'o' ('x', 'y' 'z')) 'b' 'a' 'r')
再次,然而,最有趣的部分是,既然我們現在離開Rose
樹的深度可達運行時(實際上它可以在運行時動態地改變),我們可以通過它使用運行時信息map
。
mapR :: Int -> (a -> a) -> Rose a
mapR 0 f (L a) = L (f a)
mapR n f (L a) = L a
mapR n f (Rose as) = Rose (map (mapR (n-1) f) as)
注意,不像正常map
,mapR
的功能參數不能改變的Rose
類型。這是因爲我們只映射Rose
樹的特定「層」,因此不能統一更改其中每個值的類型。要做到這一點,我們仍然必須使用我們派生的Functor
實例中的fmap
。
你可能想考慮使用鏡頭。 – Lee