Haskell - отображение нечетных помещенных значений и ровных помещенных значений по-другому

есть ли простой способ. Для взятия списка чисел скажите 123456. Затем умножьте нечетное, помещенное на три и даже помещенный на 1.

т.е. (1 * 3) + (2 * 1) + (3 * 3) + (4*1) + (5*3) + (6*1)

я думал функция карты где-нибудь вдоль строк. Но я не знаю, как отобразиться *3 на просто нечетные помещенные значения. О, и если бы Вы могли бы дать мне версию не во вводной части, которая была бы большой как фактическая функция или функции, как будто то, что это было импортированным из внешнего haskell файла

Спасибо за справку

5
задан Abstract 31 May 2010 в 07:45
поделиться

5 ответов

Хорошо, как я уже писал в комментарии, 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 здесь.

Если вы действительно не хотите использовать предопределенные функции, вы можете определить "чередующуюся карту", взяв две функции вместо одной, применив первую из них к началу списка аргументов и поменяв функции местами при рекурсивном вызове. Я предоставлю вам самим разобраться в деталях...

14
ответ дан 18 December 2019 в 09:48
поделиться

Что насчет этого, если предположить, что 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].

2
ответ дан 18 December 2019 в 09:48
поделиться

Если вы хотите сделать этот стиль без точек, нет лучшего способа, чем использование 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, но для того, кто только начинает, они могут быть проще.

0
ответ дан 18 December 2019 в 09:48
поделиться

Вы все еще можете использовать карту, просто используйте сначала zip:

let list' = zip [1..] list
in map (\(cnt,val) -> if odd cnt then val * 3 else val) list'

Выше вы можете увидеть, как сделать результат зависимым от индекса, а также от значения этого индекса. Это довольно общее решение, которое, заменив лямбда (первый аргумент map ), вы можете сделать множество вариантов. Более специализированное решение, использующее cycle и zipWith , намного короче и прекрасно читается для тех, кто знаком с Haskell.

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

0
ответ дан 18 December 2019 в 09:48
поделиться

Моя первая мысль заключалась в том, чтобы использовать карту накопления, используя параметр накопления для обозначения того, находится ли она в «четном» или «нечетном» цикле. Я вижу, что никто больше этого не делал, так что посмотрим, как получится ...

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)
1
ответ дан 18 December 2019 в 09:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: