我需要运行一个多次接受两个参数的函数.我有两个包含这些参数的列表,我希望能够使用map
或类似的东西用相应的args调用该函数.
我想调用的函数有这种类型:
runParseTest :: String -> String -> IO()
Run Code Online (Sandbox Code Playgroud)
列表创建如下:
-- 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]
Run Code Online (Sandbox Code Playgroud)
所以我们说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"
Run Code Online (Sandbox Code Playgroud)
我知道我可以创建一个帮助函数,相当容易地做到这一点,但出于兴趣,是否可以在一行中使用map
?
这是我到目前为止所做的,但显然第一个论点总是"测试":
mapM_ (runParseTest "test") libs
Run Code Online (Sandbox Code Playgroud)
如果不清楚,我道歉.如有必要,我可以提供更多信息.
Ant*_*sky 16
这是使用Hoogle的好时机!Hoogle是一个搜索Haskell 类型的搜索引擎.例如,一个Hoogle查询用于(a -> b) -> [a] -> [b]
提升map
.在这里,你有一个类型的功能String -> String -> IO ()
; 你想要一个类型的功能(String -> String -> IO ()) -> [String] -> [String] -> IO ()
.Hoogle可以经常自己概括,但它在这里遇到麻烦,所以让我们帮忙吧:你只想要(a -> a -> IO ()) -> [a] -> [a] -> IO ()
任何a
.如果您为该类型签名进行Hoogle,则第一个结果zipWithM_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()
位于Control.Monad模块中,该模块完全符合您的要求.这是一系列功能的一部分,具有不同程度的通用性:
zip :: [a] -> [b] -> [(a,b)]
,将两个列表配对,截断较短的列表.zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
,它从两个列表中的每个列表的元素上运行提供的函数; zip = zipWith (,)
.zipWithM :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c]
,就像zipWith
在monad中; zipWithM f xs ys = sequence $ zipWith f xs ys
.zipWithM_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()
,这就像zipWithM
丢弃其结果; zipWithM_ f xs ys = zipWithM f xs ys >> return () = sequence_ $ zipWith f xs ys
.zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
,我确定你的功能可以搞清楚:-)zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
,就像zipWith
在三个名单上一样; zipWith3 = zip (,,)
.zipN
和zipWithN
函数,通过zip7
/ 上传zipWith7
.(可以说,这从id :: [a] -> [a]
as zip1
和map :: (a -> b) -> [a] -> [b]
as 开始zipWith1
,这是你的问题来自哪里.)ZipList
应用函子.鉴于一些列表xs1
... xsN
,然后runZipList $ f <$> ZipList xs1 <*> ZipList xs2 <*> ... <*> ZipList xsN = runZipList $ liftAN f (ZipList xs1) ... (ZipList xsN
)行为就像zipWithN f xs1 ... xsN
.因此,在您的特定用例中,我们将进行一些额外的更改 - 以下内容:
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
Run Code Online (Sandbox Code Playgroud)
ДМИ*_*КОВ 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
Run Code Online (Sandbox Code Playgroud)
或许uncurry runParseTest
:
map (uncurry runParseTest) $ zip names libs
Run Code Online (Sandbox Code Playgroud)
或者zipWith
:
zipWith runParseTest names libs
Run Code Online (Sandbox Code Playgroud)
就像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 ()
Run Code Online (Sandbox Code Playgroud)