2013-04-25 102 views
2

我有一個[(String, [String], IO Int)]列表,我想對它進行排序。 sortBy (\x -> ...) list需要我使用IO來獲取IO Int的內部值,這意味着我不能返回Ordering,而只能使用IO Ordering來獲取sortBy函數。有什麼方法可以對列表進行排序嗎?如何根據IO Int值對列表進行排序

+0

如果您的比較函數在'IO'中,那意味着每次執行比較都會發生變化。如果你無法可重複地比較兩個元素,你如何排序列表? – 2013-04-25 00:49:47

+0

我想我們在這裏抽象地談論。你如何做像Python或Java或Javascript這樣的傳統語言? – ErikR 2013-04-25 00:53:45

+1

爲什麼不能運行'IO'動作,獲取'Int',然後對列表進行排序?每次你比較列表的一個元素時,你真的想要獲得一個可能不同的'Int'嗎? – 2013-04-25 00:56:59

回答

7

每個元組的第三個元素是IO Int,所以它的值取決於外部世界。因此,排序列表的訂單取決於外部世界。所以不,沒有辦法做一個[(String, [String], IO Int)]這是排序的值IO Int

什麼你可以做的是使IO [(String, [String], Int)]的值,然後提起sortBy功能IO單子給你另一個IO [(String, [String], Int)],將產生由Int排序的列表。這不是一個純粹的列表,但是您可以將任何其他純函數注入到monod中,以對其執行任意純計算。

像這樣的事:

import Control.Applicative 
import Data.List 

l :: [(String, [String], IO Int)] 
l = [("Foo", [], return 2), ("Bar", [], return 1)] 

f :: Monad m => (a, b, m c) -> m (a, b, c) 
f (x, y, ioz) = ioz >>= \z -> return (x, y, z) 

sl = sortBy (\(x, y, z) (x', y', z') -> compare z z') <$> mapM f l 

我應該提到,因爲它可能不是很明顯,這將運行在它們在列表中出現了最初的順序IO Int行動。但要排序它們,您必須運行它們以獲取值Int,並且它們必須在的某些順序中運行。

+0

這個monad提升正是我所需要的,謝謝。 – Witiko 2013-04-25 08:57:46

+0

@Witiko這就是我一般努力在Haskell編程的方式。將所有計算寫成純函數。在某些時候,你的計算取決於'IO'值,但是你試圖將純粹的函數提升到'IO' monad中,以儘快完成所有的實際工作。這意味着你可以完成大部分工作,就好像'IO'不存在一樣,甚至當你編寫'IO'代碼時,你也希望只提取純粹的函數並連接結果,而不是重新實現IO版本的東西。 – Ben 2013-04-25 23:24:43

相關問題