Haskell:列出对Glade条目的理解

时间:2011-08-06 07:27:30

标签: list haskell list-comprehension glade

我想制作entries :: Map(String -> Entry),以便我可以轻松按名称访问每个条目。为此,我有代码

  Just xml ←  xmlNew "blah.glade"
  ...
  entries ← fromList $ [(name,entry) | name <- entryList 
      , entry <- xmlGetWidget xml castToEntry name]

(其中entryList是条目名称列表,例如["name1","name2",...])。

但是,列表理解会出现以下错误:

   Couldn't match expected type `[t]' against inferred type `IO Entry'
    In the expression: xmlGetWidget xml castToEntry name
    In a stmt of a list comprehension:
        entry <- xmlGetWidget xml castToEntry name
    In the second argument of `($)', namely
        `[(name, entry) |
              name <- entryList, entry <- xmlGetWidget xml castToEntry name]'

我不明白为什么它会期待任何列表。任何人都可以帮忙吗?

1 个答案:

答案 0 :(得分:2)

这是因为列表理解中的<-期望右侧是列表。您尝试使用它来绑定IO操作的结果,但这仅在do表示法中有效(至少没有扩展名)。

问题是xmlGetWidget会返回IO Entry,但您想要一张Entry的地图。这意味着您必须将这些IO动作组合成更大的动作。

最后,你会想要这样的东西:

let getEntry name = do entry <- xmlGetWidget xml castToEntry name
                       return (name, entry)
entries <- fromList <$> mapM getEntry entryList

在这里,我创建了一个辅助函数getEntry :: String -> IO (String, Entry)来获取条目并将其与其名称配对。

接下来,我使用mapMgetEntry映射到名称列表上。请注意mapmapM之间的差异。如果我使用了map,我会得到一个操作列表,即[IO (String, Entry)],当我想要的是一个返回列表的操作,即IO [(String, Entry)]

现在,构建了IO操作后,我使用Map将操作符fromList转换为<$>。也称为fmap<$>将纯函数应用于IO内的事物,因此结果为IO (Map String Entry)类型。

最后,此IO操作的结果可以绑定到entries