2013-04-25 122 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

相关问题