Повторяющаяся функция, рекурсивная в Haskell

#haskell

#haskell

Вопрос:

Я пытаюсь создать функцию, которая выводит char*m n время, такое, каким ожидаемый результат был бы ["ccc","ccc"] для ввода 2 3 c . Вот что у меня есть на данный момент:

 rectangle :: Int -> Int -> Char -> [string]
rectangle n m c 
    | m > 0 = [concat ([[c]]    (rectangle n (m-1) c))] 
    | otherwise = []
  

Я могу выполнить первую часть, char*m поэтому она возвращает ["ccc"] . Дело в том, что я также хотел бы иметь возможность повторять свою строку n раз.

Я пытался использовать replicate, но, похоже, это не работает, хотя это работает, если делать это в консоли: replicate 2 (rectangle 2 3 c) .

Ответ №1:

Попробуйте реплицировать функцию таким образом:

 replicate :: Int -> a -> [a]

rectangle n m c = replicate n (replicate m c)
  

Кроме того, не забудьте указать, является ли это домашним заданием.

Комментарии:

1. Функция replicate принимает число n и значение и создает список n элементов этого значения. Таким образом, replicate 3 'a' получается "aaa" .

2. Это отличное простое решение, однако есть ли у кого-нибудь решение, в котором используется предопределенная функция? поможет мне научиться 🙂

3. @Lunar Хорошим способом научиться было бы попытаться определить replicate самостоятельно. Я не мог придумать решение, которое каким-либо образом не требует использования replicate .

4. @Lunar: Обратите внимание, что replicate это в стандартной прелюдии (или, по крайней мере, повторно экспортируется прелюдией), но я добавил подпись типа, чтобы помочь.

5. Будет ли какой-либо выигрыш в производительности, если мы сделаем что-то вроде: пусть t = replicate m c в replicate n t

Ответ №2:

В качестве дополнения к ответу рефакторинга, я думаю, что его подход является правильным. Он подразделяет проблему до тех пор, пока ее нельзя решить тривиально, используя встроенные функции. Если вы хотите внедрить свое собственное решение для целей обучения, я предлагаю вам сохранить это подразделение и перейти оттуда, реализуя свой собственный replicate. В противном случае вы получите единственную функцию, которая делает слишком много.

Итак, оставшаяся проблема заключается в реализации replicate. Моей первой идеей было бы взглянуть на исходный код replicate. Я нашел ее через hoogle, что привело меня к hackage, в котором есть ссылки на исходный код. Выдержка из исходного кода:

 replicate               :: Int -> a -> [a]
replicate n x           =  take n (repeat x)
  

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

 myReplicate                 :: Int -> a -> [a]
myReplicate n x | n <= 0    = []
                | otherwise = x : replicate (n-1) x
  

———-РЕДАКТИРОВАТЬ—————-

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

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

Для дальнейшего изучения, я уверен, вам уже указали на отличные Learn You a Haskell и Real World Haskell, но на всякий случай, если вы этого не сделали, вот они.

Комментарии:

1. Спасибо, каждая задача, которую я даю себе, кажется, терпит неудачу! и в большинстве случаев это можно сделать с помощью простых готовых функций, есть ли набор функций, которые, по вашему мнению, следует изучить и использовать, когда это возможно, таких как map, filter, replicate?

2. Опыт работы с такими функциями, как эти, определенно поможет вам. Я бы сказал, что существует базовый набор функций, которые полезно знать и использовать. Этот набор нечеткий / четко не определен, но он включает в себя общие функции списка, такие как отображение, фильтр и т.д. Я расширил свой ответ, чтобы уточнить, как они могут помочь.