Haskell (Lambdabot), 92 85 байт
x#y|x==y=[[x]]|1>0=(guard(mod x y<1)>>(y:).map(y*)<$>div x y#2)++x#(y+1)
map(1:).(#2)
Требуется Lambdabot Haskell, так как guard
требует Control.Monad
импорта. Основная функция - это анонимная функция, которая, как мне сказали, разрешена и сбрасывает пару байтов.
Спасибо Лайкони за сохранение семи байтов.
Объяснение:
Монады очень удобны.
x # y
Это наша рекурсивная функция, которая выполняет всю реальную работу. x
это число, которое мы накапливаем (произведение делителей, которые остаются в значении), и y
следующее число, которое мы должны попытаться разделить на него.
| x == y = [[x]]
Если x
равно, y
то мы закончили повторение. Просто используйте x
в качестве конца текущей цепочки gozinta и вернуть его.
| 1 > 0 =
Haskell golf-ism для "True". То есть это случай по умолчанию.
(guard (mod x y < 1) >>
Сейчас мы работаем внутри монады списка. В монаде списка у нас есть возможность сделать несколько вариантов одновременно. Это очень полезно при поиске «всего возможного» чего-либо путем истощения. В guard
заявлении говорится: «Рассматривайте следующий выбор только в том случае, если условие истинно». В этом случае рассмотрите только следующий выбор, если y
делит x
.
(y:) . map (y *) <$> div x y#2)
Если y
есть деление x
, у нас есть выбор добавления y
в цепочку gozinta. В этом случае рекурсивно вызывайте (#)
, начиная y = 2
с x
равным x / y
, так как мы хотим «вычеркнуть» то, что y
мы только что добавили в цепочку. Затем, каким бы ни был результат этого рекурсивного вызова, умножьте его значения на значения, которые y
мы только y
что проанализировали, и официально добавьте в цепочку gozinta.
++
Рассмотрим также следующий выбор. Это просто складывает два списка вместе, но монадически мы можем думать об этом, как о «выборе между выполнением этой вещи ИЛИ этой другой вещью».
x # (y + 1)
Другой вариант - просто продолжить рекурсию и не использовать значение y
. Если y
не делится, x
то это единственный вариант. Если y
делится, x
то будет выбран этот вариант, а также другой вариант, и результаты будут объединены.
map (1 :) . (# 2)
Это основная функция gozinta. Он начинает рекурсию с вызова (#)
аргумента. A 1
добавляется к каждой цепочке gozinta, потому что (#)
функция никогда не помещает их в цепочки.