我是Haskell的新手。我正在嘗試並且無法從Data.Traversable
模塊獲得traverse
功能。我無法看清楚它的意思。因爲我來自一個必要的背景,有人可以根據一個命令循環向我解釋嗎?一個僞代碼將不勝感激。謝謝。有人可以解釋Haskell中的遍歷函數
回答
我覺得最容易理解的是sequenceA
,因爲traverse
可以定義爲 如下。
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f
sequenceA
序列的結構的由左到右,與包含結果相同的形狀返回結構中的元素一起。
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
sequenceA = traverse id
你也可以認爲sequenceA
作爲扭轉了二函子的順序,例如從動作列表轉到返回結果列表的動作。
所以traverse
需要一些結構,並適用f
的每個元素在結構轉變爲一些應用性,它然後序列向上從左至右,與包含結果相同的形狀返回一個結構的那些applicatives的副作用。
您還可以將其與Foldable
進行比較,該參數定義了相關功能traverse_
。
traverse_ :: (Foldable t, Applicative f) => (a -> f b) -> t a -> f()
所以你可以看到,Foldable
和Traversable
之間的關鍵區別在於,後者可以讓你保持結構的形狀,而前者需要你結果了摺疊成一些其他的價值。
其使用的一個簡單的例子是使用一個列表作爲橫過結構,並且IO
作爲應用性:
λ> import Data.Traversable
λ> let qs = ["name", "quest", "favorite color"]
λ> traverse (\thing -> putStrLn ("What is your " ++ thing ++ "?") *> getLine) qs
What is your name?
Sir Lancelot
What is your quest?
to seek the holy grail
What is your favorite color?
blue
["Sir Lancelot","to seek the holy grail","blue"]
。當然,在這種情況下,等同於mapM
從前奏。使用其他類型的容器或使用其他應用程序時,它會變得更有趣。
traverse
與fmap
相同,只是它還允許您在重建數據結構時運行效果。
查看Data.Traversable
文檔中的示例。
data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)
的Tree
的Functor
實例是:
instance Functor Tree where
fmap f Empty = Empty
fmap f (Leaf x) = Leaf (f x)
fmap f (Node l k r) = Node (fmap f l) (f k) (fmap f r)
它會重建整個樹,應用f
到每個值。
instance Traversable Tree where
traverse f Empty = pure Empty
traverse f (Leaf x) = Leaf <$> f x
traverse f (Node l k r) = Node <$> traverse f l <*> f k <*> traverse f r
的Traversable
實例幾乎是相同的,除了構造函數的調用在應用性的風格。這意味着我們可以在重建樹的時候產生(副作用)效果。除了效果不能取決於以前的結果之外,應用程序與monad幾乎相同。在這個例子中,它意味着你不能做一些不同於某個節點的右分支的東西,這取決於重建左分支的結果。
該Traversable
類也包含一個單一版本mapM
原則上,效果可能取決於以前的結果。 (雖然你絕對不應該做的。)例如,做f
的影響,如果兩次左支是Empty
:
mapM f (Node l k r) = do
l' <- mapM f l
k' <- case l' of
Empty -> do _ <- f k; f k
_ -> f k
r' <- mapM f r
return $ Node l' k' r'
如果你想實現這個不純的語言,fmap
和traverse
會與mapM
相同,因爲沒有辦法防止副作用。您不能將其實現爲循環,因爲您必須遞歸地遍歷數據結構。這裏有一個小例子,我將如何使用Javascript:
Node.prototype.traverse = function (f) {
return new Node(this.l.traverse(f), f(this.k), this.r.traverse(f));
}
像這樣實現它限制了語言允許的效果。如果你f.e.想要非確定性(Applicative模型的列表實例)和你的語言沒有內置的,你是不走運的。
+1。第一句話是一個非常直觀的總結。 – Tarrasch
「效果」一詞的含義是什麼? – missingfaktor
@missingfaktor:它表示一個'Functor'的結構信息,不是參數的部分。 'State'中的狀態值,'Maybe'和'Either'中的失敗,'[]'中元素的數量以及'IO'中的任意外部副作用。我不關心它是一個通用術語(比如使用「空」和「追加」的「Monoid」函數,這個概念比起首先提出的概念更具有通用性),但它是相當常見的,並且足夠好。 –
traverse
原來的東西Traversable
內成爲Traversable
的事情「內部」的Applicative
,給出一個函數,使Applicative
出去了的東西。
我們使用Maybe
作爲Applicative
,列表爲Traversable
。首先,我們需要轉換功能:
half x = if even x then Just (x `div` 2) else Nothing
因此,如果一個數是偶數,我們得到的一半(一Just
內),否則我們得到Nothing
。如果一切順利的「井」,它看起來像這樣:
traverse half [2,4..10]
--Just [1,2,3,4,5]
但是......
traverse half [1..10]
-- Nothing
的原因是<*>
功能是用於構建的結果,而當其中一個參數是Nothing
,我們得到Nothing
回來。
又如:
rep x = replicate x x
該函數生成長度x
的列表與該內容x
,例如rep 3
= [3,3,3]
。 traverse rep [1..3]
的結果是什麼?
我們得到[1]
,[2,2]
和[3,3,3]
使用rep
的部分搜索結果。現在列表的語義爲Applicatives
是「採取所有組合」,例如, (+) <$> [10,20] <*> [3,4]
是[13,14,23,24]
。
[1]
和[2,2]
的「所有組合」是[1,2]
的兩倍。兩次[1,2]
和[3,3,3]
的所有組合是[1,2,3]
的六倍。因此,我們有:
traverse rep [1..3]
--[[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
+1,我發現這個答案最容易理解的三個。 – missingfaktor
你最終的結果讓我想起[this](http://www.willamette.edu/~fruehr/haskell/evolution.html)。 – hugomg
@missingno:是的,他們錯過了'fac n = length $ traverse rep [1..n]' – Landei
traverse
是循環。其實現取決於要遍歷的數據結構。這可能是一個List,Tree,Maybe,Seq(ence)或者任何具有通過某種方法遍歷的通用方法。像一個for循環或遞歸函數。一個數組有一個for循環,一個List while循環,一個Tree或者。遞歸或堆棧與while循環的組合;但在函數式語言中,您不需要這些繁瑣的循環命令:將循環的內部部分(以函數的形式)與數據結構以更直接的方式組合起來,而不是冗長的。
使用Traversable typeclass,你可能會寫出更獨立和多功能的算法。但我的經驗表明,Traversable通常只用於將算法粘貼到現有的數據結構。不需要爲不同的數據類型編寫類似的函數也是很好的。
它有點像fmap
,不同之處在於你可以在mapper函數中運行副作用,這也會改變結果類型。
想象一下表示數據庫中用戶ID的整數列表:[1, 2, 3]
。如果你想fmap
這些用戶ID到用戶名,你不能使用傳統的fmap
,因爲在函數內你需要訪問數據庫來讀取用戶名(這需要一個副作用 - 在這種情況下,使用IO monad )。
的traverse
的簽名是:
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
隨着traverse
,你可以做的副作用,因此,您的映射用戶ID碼到用戶名的樣子:
mapUserIDsToUsernames :: (Num -> IO String) -> [Num] -> IO [String]
mapUserIDsToUsernames fn ids = traverse fn ids
有還有一個叫做mapM
的功能:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
任何使用mapM
都可以用traverse
代替,但不能用其他方式。 mapM
通常表現優於traverse
,但mapM
僅適用於帶單子的單子,而traverse
更具通用性。
如果您只是想達到副作用並且不返回任何有用的值,則有traverse_
和mapM_
版本的這些函數,它們都會忽略函數的返回值並且速度稍快。
- 1. 有人可以向我解釋這些Haskell函數嗎?
- 2. 有人可以詳細解釋這個haskell函數的簽名嗎?
- 3. 有人可以向我解釋PHP中的pack()函數嗎?
- 4. 有人可以解釋以下奇怪的函數聲明嗎?
- 5. 有人可以解釋「 - '0'」
- 6. 有人可以在Objective-C中解釋函數名嗎?
- 7. 有人可以解釋參數autovacuum_naptime嗎?
- 8. 有人可以解釋howtonode包裝成語的函數嗎?
- 9. 有人可以解釋在JavaScript getCookie()while循環的函數嗎?
- 10. 有人可以解釋函數mkpp和ppval的行爲嗎?
- 11. strtotime()函數需要解釋,有人可以解釋這一行嗎?
- 12. 如何遍歷具有Haskell monadic函數的樹的元素?
- 13. 有人可以解釋這個遞歸函數MongooseJS
- 14. 有人可以解釋這個C函數嗎?
- 15. SQL Server ISDATE()函數 - 有人可以解釋這一點嗎?
- 16. 有人可以解釋這個遞歸函數嗎?
- 17. 任何人都可以解釋在Python中的lambda函數?
- 18. 有人可以解釋iOS4的CMTime嗎?
- 19. 有人可以解釋的ATTR?
- 20. Scala函數中的參數列表。有人可以解釋代碼嗎?
- 21. 樹與Haskell遍歷
- 22. 有人可以向我解釋一個函數可以等於0嗎?
- 23. 函數在Haskell可以解決方程
- 24. 有人可以在Haskell中向我解釋這個Integer模塊行爲嗎?
- 25. 有人可以解釋__declspec(裸體)嗎?
- 26. 有人可以請解釋輸出java
- 27. 有人可以解釋這個查詢
- 28. 有人可以解釋公式
- 29. 有人可以解釋RemoteViews GC行爲?
- 30. 有人可以解釋SQLiteOpenHelper getType
文章[迭代器模式的本質](https://www.cs.ox.ac.uk/jeremy.gibbons/publications/iterator.pdf)可能會有幫助,因爲它構建了遍歷步驟的概念步。一些先進的概念雖然 – Jackie