Рекурсия в Хаскелле

75
5

Я все еще участвую в Haskell, и я делаю несколько упражнений, но я в пробке. Таким образом, у меня есть функция, называемая "роман", которая берет 2 строки и Int (novel :: (String, String, Int) → String) для своих аргументов. Новый ввод/вывод должен выглядеть следующим образом:

> novel ("Rowling", "Harry Potter", 1998)
"Harry Potter (Rowling, 1998)"

Это мой код для моей новой функции, которая работает, как описано выше:

novel :: (String, String, Int) -> String
novel (author, book, year) = book ++ " (" ++ author ++ ", " ++ (show year) ++ ")"

Я пытаюсь написать новую функцию под названием "cite" (cite :: [(String, String, Int)] → String). Cite ввод/вывод должен выглядеть следующим образом:

> cite [("author1", "book1", year1), ("author2", "book2", year2), ("author3", "book3", year3)]
"book1 (author1, year1)
book2 (author2, year2)
book3 (author3, year3)"

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

Что я пробовал:

cite :: [(String, String, Int)] -> String                -- | Listed arguments
cite [] = "" -- | Base Case
cite x:xs = [(novel (author, book, year)), (novel (author, book, year)), (novel (author, book, year))]

Это честно, насколько я понял. Очевидно, что это не сработает, но я не уверен, что делать дальше.

спросил(а) 2021-01-19T17:05:16+03:00 2 месяца, 3 недели назад
1
Решение
107

Возможно, это даст вам начало:

cite :: [(String, String, Int)] -> String
cite [] = ""
cite (x:xs) = undefined -- put your code that recursively calls cite in here, hint: use ++ and "\n\"

Соответствует шаблону (x:xs), дайте мне первый элемент в списке x и хвост списка xs. Это было бы так же, как написать это:

cite xs' = let x = head xs'
xs = tail xs'
in undefined -- your code here

Или даже

cite xs' = undefined -- your code here
where
x = head xs'
xs = tail xs'

Надеюсь, это поможет вам в правильном направлении.

EDIT: OP попросил, как это сделать рекурсивно, ниже мой первоначальный ответ:

Вероятно, вы должны переписать свой базовый код, чтобы сказать cite [] = "". Это не имеет особого значения, но это поможет с чтением кода.

Позвольте начать, поставив ": t map novel" в ghci, чтобы узнать, что вы получаете:

> :t map novel
map novel :: [([Char], [Char], Int)] -> [[Char]]

Который мы можем переписать как: map novel :: [(String, String, Int)] → [String]

Как? Поскольку map выполняет преобразование одного типа a в другой тип b и применяет его к каждому элементу в списке. Первым аргументом map является любая функция, которая принимает один аргумент. Именно то, что делает novel.

Но это не дает нам то, что вам нужно, мы получим список строк вместо строки:

> cite [("author1", "book1", year1), ("author2", "book2", year2), ("author3", "book3", year3)]
["book1 (author1, year1)","book2 (author2, year2)","book3 (author3, year3)"]

И вы хотите, чтобы это была одна строка, разделенная символом новой строки "\n". Есть ли функция, которая может принимать список строк и объединять их в одну строку, но интеркалировать разделитель между ними?

Сначала опишите такую функцию: String → [String] → String. Затем мы запустили его в Google, чтобы узнать, что получим: https://www.haskell.org/hoogle/?hoogle=String+-%3E+%5BString%5D+-%3E+String

Ах, эта вторая функция intercalate как то, что нам нужно. Он не просто работает на Strings, он работает в любом списке. Как это сработает? Что-то вроде этого:

> import Data.List (intercalate)
> intercalate "\n" ["List","Of","Strings"]
"List\nOf\nStrings"

Итак, теперь вы можете комбинировать интеркаляцию и карту, чтобы получить то, что вам нужно. Я оставлю определение для cite до вас.

EDIT: Полностью забыл, для этого есть специальная функция. Если вы просто ищете [String] → String в Hoogle, вы найдете unlines

ответил(а) 2021-01-19T17:05:16+03:00 2 месяца, 3 недели назад
62

Там достаточно простой способ сделать это.

Во-первых, сопоставьте novel каждому элементу данного списка, затем используйте Data.List.intersperse чтобы заполнить пробелы Data.List.intersperse символами. Это моя реализация:

import Data.List (intersperse)

cite :: [(String, String, Int)] -> String
cite bs = intersperse '\n' (map novel bs)

Или, в более элегантном стиле без очков:


cite = intersperse '\n' . map novel

Можно также написать хорошую, эффективную рекурсивную функцию:

cite []     = ""
cite [x] = novel x
cite (x:xs) = novel x ++ '\n' : cite xs

В будущих проблемах, таких как это, имейте в виду такие функции, как map и foldr - это две из наиболее неотъемлемых частей Haskell и функционального программирования. Кроме того, ваши совпадения шаблонов должны быть заключены в круглые скобки.

ответил(а) 2021-01-19T17:05:16+03:00 2 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема