Роспись строительная в Хаскеле - PullRequest
1 голос
/ 03 декабря 2009

У меня есть следующая рекурсивная функция для проекта euler вопрос №. 74

chain n | n `elem` xs = length xs
        | otherwise = (chain (sumFac n)) : xs
fac n = foldl (*) 1 $ enumFromTo 1 n
sumFac n = sum $ map fac $ decToList n

За исключением того, что я не знаю правильный синтаксис для построения списка на chain n, чтобы он формировал список xs и затем возвращал длину xs, когда число снова появляется в списке xs и начинает цикл.

Как бы я исправил свою цепочку, чтобы она работала?

Ответы [ 3 ]

5 голосов
/ 03 декабря 2009

Используйте вспомогательную функцию:

chain n = go [n]
  where go xs | next `elem` xs = reverse $ next : xs
              | otherwise      = go (next:xs)
          where next = sumFac $ head xs

fac = product . enumFromTo 1

sumFac = sum . map fac . map digitToInt . show

Как видите, вы были близки к тому, что хотели, но вы размыли их вместе.

Ради интереса я бросил в бессмысленных эквивалентах fac и sumFac.

Вот определение без точки, которое использует шаблон представления (но, увы, похоже, щекочет # 2395 ):

{-# LANGUAGE ViewPatterns #-}

chain = head . filter hasDup . tail . inits . iterate sumFac
  where hasDup (reverse -> (x:xs)) = x `elem` xs
1 голос
/ 03 декабря 2009

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

Лучшим подходом было бы создать бесконечный список чисел, сгенерированных проблемой, и затем обнаружить внутри нее циклы. Вы можете получить бесконечный список для начального значения "n", используя

numberSequence n = iterate sumFac n

Тогда ищи циклы. Вы должны сравнить каждый номер со всеми предыдущими номерами. Простой, но неэффективный способ состоит в том, чтобы создать список по ходу дела, сверяя каждое число с текущим списком, а затем добавляя число к списку при рекурсивном вызове. Более эффективным решением было бы использование Data.Set.

Кстати, fac n = product [1..n]. Ваша версия работает, но излишне многословна. (На самом деле, если вы подставите определение «product» и desugar «[1..n]», вы получите свою версию).

0 голосов
/ 03 декабря 2009

Не знаю, если это так просто, но вы не указали, что хотите получить голову и хвост вместо всего списка в параметрах.

chain [n:xs] | n `elem` xs = length xs
             | otherwise = chain (sumFac n) : xs
fac n = foldl (*) 1 $ enumFromTo 1 n
sumFac n = sum $ map fac $ decToList n

У меня нет decToList, поэтому я не проверял, работает это или нет. Классная работа, хотя, я многому научился, читая это.

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