Haskell 使用带有两个列表而不是一个列表的映射。你会筑巢吗?
我需要运行一个多次使用两个参数的函数。我有两个包含这些参数的列表,我希望能够使用Haskell 使用带有两个列表而不是一个列表的映射。你会筑巢吗?,haskell,mapping,Haskell,Mapping,我需要运行一个多次使用两个参数的函数。我有两个包含这些参数的列表,我希望能够使用map或类似的东西来调用带有相应参数的函数 我要调用的函数具有以下类型: runParseTest :: String -> String -> IO() 创建的列表如下所示: -- Get list of files in libraries directory files <- getDirectoryContents "tests/libraries" -- Filter out ".."
map
或类似的东西来调用带有相应参数的函数
我要调用的函数具有以下类型:
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]
runParseTest "test1.js" "tests/libraries/test1.js"
runParseTest "test2.js" "tests/libraries/test2.js"
runParseTest "test3.js" "tests/libraries/test3.js"
我知道我可以很容易地创建一个助手函数,但是出于兴趣,是否可以使用map
在一行中创建
到目前为止,这就是我的观点,但显然第一个论点总是“测试”:
如果不清楚,我道歉。如有必要,我可以提供更多信息
假设名称包含[“test1.js”、“test2.js”、“test3.js”]
libs包含[“tests/libraries/test1.js”、“tests/libraries/test2.js”、“tests/libraries/test3.js”]
我想这样称呼他们:
-- 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]
runParseTest "test1.js" "tests/libraries/test1.js"
runParseTest "test2.js" "tests/libraries/test2.js"
runParseTest "test3.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
或者可能未经修正的runParseTest
:
map (uncurry runParseTest) $ zip names libs
或使用zipWith
:
zipWith runParseTest names libs
如前所述,单子有一些类似物:
> :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 ()
你在找我
你说你可以写一个助手函数来实现这一点。这意味着您知道要查找的函数的类型。在这种情况下,您可以使用
(试试:Monad m=>[a]->[b]->m())这是一个很好的使用时机!Hoogle是一个搜索Haskell类型的搜索引擎。例如,一个对的Hoogle查询就会出现。这里有一个类型为
String->String->IO()
的函数;您需要类型为(String->String->IO())->[String]->[String]->IO()
的函数。Hoogle通常可以自己进行泛化,但是它在这里遇到了问题,所以让我们来帮助它:对于任何a
,您只需要(a->a->IO())->[a]->[a]->IO()
。如果需要,第一个结果将出现在模块中,该模块正是您想要的。这是一系列功能的一部分,具有不同程度的通用性:
- ,它将两个列表配对,截断较短的一个
- ,它对两个列表中的每个元素运行提供的函数
zip=zipWith(,)
- ,类似于单子中的
zipWith
zipWithM f xs ys=序列$zipWithf xs ys
- ,类似于zipWithM,但丢弃其结果
zipWithM_fxs ys=zipWithM f xs ys>>return()=sequence_$zipWith f xs ys
- ,我相信您可以了解其功能:-)
- ,类似于三个列表上的
zipWith
zipWith3=zip(,)
- 一系列
和zipN
函数,通过zipWithN
/zip7
上升。(可以说,这是从aszipWith7
和aszip1
开始的,这就是您的问题的来源。)zipWith1
- 以及最一般的应用函子。给定一些列表,
…xs1
,然后xsN
)的行为与zipWithN f xs1一样。。。xsNrunZipList$f ZipList xs1 ZipList xs2。。。ZipList xsN=runZipList$liftAN f(ZipList xs1)。。。(ZipList 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
导入数据列表(isPrefixOf)
...
--我去掉了'head',因为它是一个偏函数,我更喜欢'map',而不是
--列出对简单事物的理解
do files在等待答案的过程中,我根据map
和mapM
的源代码,创建了一个名为map2M\
的新函数,并创建了自己的解决方案:
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)
这就是我要找的。实际上,我已经编写了一个名为map2M\uu
的新函数,我将发布该函数,但我确信这是一种“正确”的方法。