Использование карты с двумя списками, а не одним. Ты можешь гнездиться? - PullRequest
7 голосов
/ 26 февраля 2012

Мне нужно запустить функцию, которая принимает два аргумента несколько раз. У меня есть два списка, содержащих эти аргументы, и я хотел бы иметь возможность использовать 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]

Итак, допустим, что 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 ]

16 голосов
/ 26 февраля 2012

Это прекрасное время для использования Hoogle !Hoogle - это поисковая система для поиска на Haskell types .Например, запрос 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 , который делает именно то, что вы хотите.Это часть семейства функций с различной степенью общности:

Итак, в вашем конкретном случае использования мы получим - с несколькимидополнительные изменения - следующие:

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
11 голосов
/ 26 февраля 2012

Итак, допустим, что имена содержат ["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

И, как сказал Озгур , есть несколько аналогов для монад:

> :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 ()
3 голосов
/ 26 февраля 2012

Вы ищете zipWithM_ .

Вы говорите, что могли бы написать вспомогательную функцию, которая делает это. Это означает, что вы знаете тип функции, которую вы ищете. В таких случаях вы можете использовать hoogle .

(Попробуйте: Монада m => [a] -> [b] -> m ())

1 голос
/ 26 февраля 2012

В ожидании ответов я создал собственное решение с новой функцией 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...