есть ли простой способ. Для взятия списка чисел скажите 123456. Затем умножьте нечетное, помещенное на три и даже помещенный на 1.
т.е. (1 * 3) + (2 * 1) + (3 * 3) + (4*1) + (5*3) + (6*1)
я думал функция карты где-нибудь вдоль строк. Но я не знаю, как отобразиться *3 на просто нечетные помещенные значения. О, и если бы Вы могли бы дать мне версию не во вводной части, которая была бы большой как фактическая функция или функции, как будто то, что это было импортированным из внешнего haskell файла
Спасибо за справку
Хорошо, как я уже писал в комментарии, zipWith (*) (cycle [3,1]) xs
- это то, что вы ищете. Но сначала небольшая придирка: главой списка я бы назвал нулевой элемент, поэтому я поменял местами 1 и 3 :-)
Давайте рассмотрим простой пример; пусть xs
будет [9,8,7,3,2]
. cycle [3,1]
просто повторяет свой аргумент снова и снова, так что получится бесконечный список, начинающийся с [3,1,3,1,3,1,...]. Что делает zipWith f xs ys
, так это берет головной элемент xs
и головной элемент ys
и применяет f
(которая должна быть функцией двух аргументов) к этим элементам - результат f
затем идет впереди результата zipWith
. Если один из xs или ys становится пустым, мы закончили; в противном случае мы просто продолжаем.
Итак, первым элементом результата будет (3 * 9)
, затем (1 * 8)
, (3 * 7)
, (1 * 3)
, (3 * 2)
и все!
Вы можете посмотреть определение zipWith
здесь.
Если вы действительно не хотите использовать предопределенные функции, вы можете определить "чередующуюся карту", взяв две функции вместо одной, применив первую из них к началу списка аргументов и поменяв функции местами при рекурсивном вызове. Я предоставлю вам самим разобраться в деталях...
Что насчет этого, если предположить, что xs
- это ваш список чисел:
map (uncurry ($)) (zip (cycle [((*) 1), ((*) 3)]) xs)
Вот как это работает:
[((*) 1), ((*) 3)]
- это список, содержащий две функции. Первый умножает число на единицу; второй умножает число на три.
cycle [...]
создает бесконечный список этих двух функций, повторяющихся одну за другой, [× 1, × 3, × 1, × 3 ...]
zip (cycle [ ...]) xs
берет ваши числа и связывает их с функциями. Итак, если xs
равно [1..6], то вы получите [(× 1, 1), (× 3, 2), (× 1, 3), (× 3, 4), (× 1, 5), (× 3, 6)].
Функция $ :: (a -> b) -> a -> b
является комбинатором; он берет функцию a → b и применяет ее к значению. Итак, map (uncurry ($)) (zip ...)
берет список пар (функция, число) и применяет функцию к числу. Вам нужно uncurry
, потому что список содержит пары, поэтому сигнатура функции для отображения должна быть ((a -> b), a) -> b
.
В результате вы получите список; в этом случае [1, 6, 3, 12, 5, 18].
Если вы хотите сделать этот стиль без точек, нет лучшего способа, чем использование cycle
и какой-либо формы zip
. (Point-free означает, грубо говоря, "без именования let-bound или lambda-bound переменных"). У меня два вопроса:
cycle
и другими менее известными списковыми функциями (их должно быть сто)?Чем более общей будет ваша проблема и чем более знакомы ваши читатели, тем с большей вероятностью я буду рекомендовать стиль без точек. Для разового решения, рассчитанного на читателей, не очень знакомых с Haskell, я мог бы попробовать рекурсивную функцию:
mult31 [] = 0
mult31 [x:x':xs] = x * 3 + x' * 1 + mult31 xs
mult31 [x] = x * 3
Или, если вы хотите поумничать, можно использовать пару чередующихся функций:
mult31 = m3
where m3 (x:xs) = x * 3 + m1 xs
m3 [] = 0
m1 (x:xs) = x * 1 + m3 xs
m1 [] = 0
Любая из этих функций покажется ветерану Haskell менее естественной, чем та, в которой используется функция zip с cycle
, но для того, кто только начинает, они могут быть проще.
Вы все еще можете использовать карту, просто используйте сначала zip:
let list' = zip [1..] list
in map (\(cnt,val) -> if odd cnt then val * 3 else val) list'
Выше вы можете увидеть, как сделать результат зависимым от индекса, а также от значения этого индекса. Это довольно общее решение, которое, заменив лямбда (первый аргумент map
), вы можете сделать множество вариантов. Более специализированное решение, использующее cycle
и zipWith
, намного короче и прекрасно читается для тех, кто знаком с Haskell.
отредактировано и уточнено после утверждения, что это не домашнее задание.
Моя первая мысль заключалась в том, чтобы использовать карту накопления, используя параметр накопления для обозначения того, находится ли она в «четном» или «нечетном» цикле. Я вижу, что никто больше этого не делал, так что посмотрим, как получится ...
import Data.List (mapAccumL)
yourFunc = snd . mapAccumL mult True -- 'True' represents an odd index, starting from 1
where
mult True x = (False, 3 * x)
mult False x = (True , x)