使用带有两个列表的映射而不是一个。你能窝吗?

时间:2012-02-25 22:16:31

标签: haskell mapping

我需要运行一个多次接受两个参数的函数。我有两个包含这些参数的列表,我希望能够使用map或类似的东西来调用带有相应args的函数。

我要调用的函数有这种类型:

runParseTest :: String -> String -> IO()

列表的创建方式如下:

-- Get list of files in libraries directory
files <- getDirectoryContents "tests/libraries"
-- Filter out ".." and "." and add path
let names = filter (\x -> head x /= '.') files
let libs = ["tests/libraries/" ++ f | f <- names]

因此,我要说names包含["test1.js", "test2.js", "test3.js"]libs包含["tests/libraries/test1.js", "tests/libraries/test2.js", "tests/libraries/test3.js"]

我想这样称呼他们:

runParseTest "test1.js" "tests/libraries/test1.js"
runParseTest "test2.js" "tests/libraries/test2.js"
runParseTest "test3.js" "tests/libraries/test3.js"

我知道我可以创建一个帮助函数,可以很容易地做到这一点,但是出于兴趣,是否可以使用map在一行中完成?

这是我到目前为止所做的,但显然第一个论点总是“测试”:

mapM_ (runParseTest "test") libs

如果不清楚,我道歉。如有必要,我可以提供更多信息。

4 个答案:

答案 0 :(得分:16)

这是使用Hoogle的好时机! Hoogle是搜索Haskell 类型的搜索引擎。例如,(a -> b) -> [a] -> [b]的Hoogle查询提升map。在这里,你有一个String -> String -> IO ()类型的函数;你想要一个(String -> String -> IO ()) -> [String] -> [String] -> IO ()类型的函数。 Hoogle可以经常自我概括,但它在这里遇到了麻烦,所以让我们帮忙吧:你只需要(a -> a -> IO ()) -> [a] -> [a] -> IO ()任何a。如果您Hoogle for that type signature,则zipWithM_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()模块中的第一个结果是Control.Monad,它完全符合您的要求。这是一系列功能的一部分,具有不同程度的通用性:

因此,在您的特定用例中,我们将进行一些额外的更改 - 以下内容:

import Data.List (isPrefixOf)

...

-- I got rid of `head` because it's a partial function, and I prefer `map` to
-- list comprehensions for simple things    
do files <- getDirectoryContents "tests/libraries"
   let names = filter (not . ("." `isPrefixOf`)) files
       libs  = map ("tests/libraries/" ++) names
   zipWithM_ runParseTest names libs

答案 1 :(得分:11)

  

让我们说名字包含["test1.js", "test2.js", "test3.js"]   和libs包含["tests/libraries/test1.js", "tests/libraries/test2.js", "tests/libraries/test3.js"]

     

我想这样称呼他们:

     

runParseTest "test1.js" "tests/libraries/test1.js"    runParseTest "test2.js" "tests/libraries/test2.js"   runParseTest "test3.js" "tests/libraries/test3.js"

可以使用zip

执行此操作
map (\(a,b) -> runParseTest a b) $ zip names libs

或者uncurry runParseTest

 map (uncurry runParseTest) $ zip names libs

zipWith

 zipWith runParseTest names libs

Ozgur一样,monad有一些类似的东西:

> :t zipWithM
zipWithM :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c]
> :t zipWithM_
zipWithM_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()

答案 2 :(得分:3)

您正在寻找zipWithM_

你说你可以编写一个帮助函数来执行此操作。这意味着您知道要查找的功能的类型。在这种情况下,您可以使用hoogle

(尝试:Monad m =&gt; [a] - &gt; [b] - &gt; m())

答案 3 :(得分:1)

在等待答案的同时,我根据map2M_map的源代码创建了一个名为mapM_的新功能的自己的解决方案:

map2 :: (a -> b -> c) -> [a] -> [b] -> [c]
map2 _ [] _          = []
map2 _ _ []          = []
map2 f (a:as) (b:bs) = f a b : map2 f as bs

map2M_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()
map2M_ f as bs =  sequence_ (map2 f as bs)