Давайте начнем с того, что у вас есть.
something n = [[ 2 * x + 1 | x <- xs]|xs <- [3..n],i <- [1..],j <-[1..] ,xs == i+j+2*i*j,i<=j,i>=1]
Основная проблема здесь в том, что вам не нужно понимание вложенного списка.
something n = [ 2 * x + 1 | x <- [3..n], i <- [1..], j <- [1..], x == i+j+2*i*j, i<=j, i>=1]
Это скомпилируется.Но, как вы подозреваете, с этим фрагментом кода гораздо больше проблем.
Давайте начнем с условий.Тестирование на i>=1
является излишним, учитывая, что i <- [1..]
.
something n = [ 2 * x + 1 | x <- [3..n], i <- [1..], j <- [1..], x == i+j+2*i*j, i<=j]
Аналогично, мы можем избавиться от условия i<=j
, если мы начнем j
с i
вместо 1
.
something n = [ 2 * x + 1 | x <- [3..n], i <- [1..], j <- [i..], x == i+j+2*i*j]
Должно быть понятно, что значения j
больше (n - i) `div` (1 + 2 * i)
не могут привести к x
≤ n
.
something n = [ 2 * x + 1 | x <- [3..n], i <- [1..], j <- [i .. (n - i) `div` (1 + 2 * i)], x == i+j+2*i*j]
Аналогичнозначения i
или n `div` 3
или выше не могут привести к x
≤ n
.
something n = [ 2 * x + 1 | x <- [3..n], i <- [1 .. (n `div` 3) - 1], j <- [i .. (n - i) `div` (1 + 2 * i)],
x == i+j+2*i*j]
. На данный момент мы сделали достаточно для something
, чтобы фактически генерировать результаты.Но есть повторяющиеся значения (например, когда (i, j) равно (1,7) или (2,4), вы получаете x = 22), что, я полагаю, вам не нужно.
Мы фильтруемих с использованием nub
из Data.List
.
something n = nub [ 2 * x + 1 | x <- [3..n], i <- [1 .. (n `div` 3) - 1],
j <- [i .. (n - i) `div` (1 + 2 * i)], x == i+j+2*i*j]
Нет необходимости проверять, что x
удовлетворяет условию, когда мы могли бы построить x
, чтобы удовлетворить это условие в первую очередь.(Вы захотите убедиться, что 3 ≤ x ≤ n все еще.) Это более эффективно.
something n = nub [ 2 * x + 1 | i <- [1 .. (n `div` 3) - 1], j <- [1 .. (n - i) `div` (1 + 2 * i)],
let x = i+j+2*i*j]
Результаты больше не отображаются в порядке возрастания, поэтому давайте удостоверимся, что они есть.
something n = sort $ nub [ 2 * x + 1 | i <- [1 .. (n `div` 3) - 1], j <- [1 .. (n - i) `div` (1 + 2 * i)],
let x = i+j+2*i*j]
В точке стиля удвоение и добавление единицы - это отдельный расчет от гарантии того, что x может быть выражено как i + j + 2 * i * j, поэтому давайте разделим их.
something n = sort $ map f $ nub [ x | i <- [1 .. (n `div` 3) - 1], j <- [1 .. (n - i) `div` (1 + 2 * i)],
let x = i+j+2*i*j]
where f x = 2 * x + 1
Это позволяет нам избавиться от x из списка.
something n = sort $ map f $ nub [ i+j+2*i*j | i <- [1 .. (n `div` 3) - 1],
j <- [1 .. (n - i) `div` (1 + 2 * i)]]
where f x = 2 * x + 1
Готово.