Объедините список списков со списком, используя функцию в Haskell - PullRequest
0 голосов
/ 29 октября 2018

Я хочу иметь возможность применять функцию между каждым элементом списка ввода и каждым элементом каждого подсписка в списке списков, например так:

mapFunc :: (a -> b -> c) -> [[a]] -> [b] -> [[c]]

Например: mapFunc (*) [[1,2,3],[4,5,6]] [1,2,3] должен дать мне: [[1,4,9],[4,10,18]].

Есть ли конкретный способ сделать это в Haskell?

Я знаю, что, вероятно, требуется комбинация zipWith и map в некотором роде, и я пробовал их, но на самом деле не смог решить мою проблему

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Итак, мы должны иметь

mapFunc (*)  [[1,2,3], [4, 5, 6]]    [1,2,3] 
     ==      [[1,4,9], [4,10,18]]

и так, также

mapFunc (*)  [[1,2,3], [4, 5, 6], [7, 8, 9, 10]]     [1,2,3]
     ==      [[1,4,9], [4,10,18], [7, 14, 27]  ]
-- and
mapFunc (*)  [[1,2,3]]                               [1,2,3] 
     ==      [[1,4,9]]
-- and
mapFunc (*)           [[4, 5, 6], [7, 8, 9, 10]]     [1,2,3]
     ==               [[4,10,18], [7, 14, 27]  ]

Таким образом,

mapFunc (*) ([[1,2,3]] ++ [[4, 5, 6], [7, 8, 9, 10]])    [1,2,3]
     == (mapFunc (*) 
             [[1,2,3]]                                   [1,2,3])
                       ++
             (mapFunc (*) [[4, 5, 6], [7, 8, 9, 10]]     [1,2,3])

Хотя в этих конкретных числах нет ничего особенного, поэтому мы обязательно должны иметь

mapFunc (*) (    [xs]      ++              xss       )     ys   =
  = (mapFunc (*) [xs]  ys  ++  mapFunc (*) xss  ys)
  = ([g           xs  ys]  ++  mapFunc (*) xss  ys)

потому что, как мы видим из наших примеров, (\xss -> mapFunc (*) xss ys) является сохраняющим длину преобразованием.

Так какой должна быть эта g функция?

пена, промыть, повторить:

Мы должны иметь

g   [1,2,3]   [1,2,3] == [1,4,9]
g   [4,5,6]   [1,2,3] == [4,10,18]
g   [7,8,9,10]  [1,2,3] == [7,14,27]

и, таким образом, снова обобщая, поскольку числа сами по себе ничего особенного,

g  xs  ys  =  [ (*) x y | x <- xs | y <- ys ]

и это все.

0 голосов
/ 30 октября 2018

Я знаю, что, вероятно, требуется комбинация zipWith и map

Вы на правильном пути.

Учитывая два списка xss и ys, вы хотите взять каждый элемент xss :: [[a]], являющийся списком xs :: [a], и сжать его с помощью ys :: [b], используя f :: a -> b -> c. «Каждый элемент» предлагает map (или понимание списка), так что вы можете сделать предположение, содержащее «дыру», в которой компилятор сообщит тип:

mapFunc :: (a -> b -> c) -> [[a]] -> [b] -> [[c]]
mapFunc f xss ys = map (\xs -> _) xss

-- or,
mapFunc f xss ys = [_ | xs <- xss]

Тип этого отверстия [c] в любом случае; компилятор также дает нам список вещей в области видимости, которые могут быть полезны для заполнения дыры:

xs :: [a]
ys :: [b]
xss :: [[a]]
f :: a -> b -> c
mapFunc :: (a -> b -> c) -> [[a]] -> [b] -> [[c]]

Глядя на тип zipWith, следует выяснить, как заполнить эту дыру, т. Е. Как создать значение с типом [c], комбинируя значения, которые у вас есть в области видимости:

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

В качестве упражнения вы также можете вручную вставить определения map и zipWith, чтобы понять, как бы вы написали это, используя ручную рекурсию. Полезное расширение здесь - {-# LANGUAGE ScopedTypeVariables #-}, которое позволяет вам определять область действия типов a, b и c, используя квантификатор forall, так что вы можете разбить проблему на локальные определения и дать сигнатуры типов для каждой части так, чтобы эти сигнатуры типов могли повторно использовать переменные одного типа a, b и c. Попробуйте сами, начиная с этой подписи:

mapFunc :: forall a b c. (a -> b -> c) -> [[a]] -> [b] -> [[c]]

А если вы застряли, ниже приведена подсказка о том, как мне структурировать решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...