Начнем с того, что у вас есть.
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
Сделанный.
person
dave4420
schedule
13.10.2011