Полагаю, что первый Int в Graph является границей для ваших узлов (например, 6, если узлы находятся в [1..6]
).
Поэтому вам нужна функция, которая возвращает треугольники графа, поэтому тип может быть:
triangles :: Graph -> [(Int, Int, Int)]
Теперь треугольник существует всякий раз, когда для 3 узлов, скажем, x
y
и z
, все комбинации возвращают значения True
- g
.
Итак, вы можете рассмотреть возможность создания всех этих комбинаций (возможно, избегая тех, которые эквивалентны через переупорядочение), и отфильтровывать только те, которые подтверждают критерий:
isTriangle :: Graph -> (Int, Int, Int) -> Bool
isTriangle (_, g) (x, y, z) == g x y && g y z && g x z
Для этого вы можете использовать список или функцию filter типа (a -> Bool) -> [a] -> [a]
Ответ на ваш первый комментарий:
Во-первых, вам нужно реализовать функцию triangles
, которая является причиной ошибки. Но, как вы сделали в test
, вы можете просто генерировать эти треугольники на лету.
Теперь вы написали:
test = filter (isTriangle) [(x,y,z) | x <- [1..3], y <- [1..3], z <- [1..3]]
Об этом две вещи:
- Во-первых, вам не нужны круглые скобки вокруг
isTriangle
для того, что вы написали, но это неверно, поскольку isTriangle
ожидает график в качестве первого параметра
Во-вторых, вы получите много дубликатов, и если вы хотите, вы можете предотвратить это, не создавая их в первую очередь:
test = filter (isTriangle) [(x,y,z) | x <- [1..3], y <- [1..x], z <- [1..y]]
В качестве альтернативы, вы можете отключить функцию filter
, предоставив защиту в синтаксисе понимания списка, например:
[(x, y, z) | x <- [1..3], y <- [1..x], z <- [1..y], isTriangle yourGraph (x, y, z)]
Теперь я позволю вам продолжить с деталями. Вы захотите сделать это функцией, которая принимает график, и заменить это 3
числом узлов в графе, а yourGraph указанным графиком.
Поскольку вы решили использовать понимание списков, забудьте о генерирующей функции, о которой я писал ранее, ее целью было просто генерировать ввод для filter
, но при подходе к пониманию списков она вам не обязательно понадобится.
Ответ на второй комментарий:
Вы хотите написать функцию:
triangles :: Graph -> [(Int, Int, Int)]
triangles (n, g) = [(x, y, z) | ...]
...
должны быть заменены правильными вещами из более ранних (диапазоны для x, y и z, а также предикат isTriangle).
Кроме того, вы можете сократить это в двух функциях:
allTriangles :: Int -> [(Int, Int, Int)]
allTriangles n = [(x, y, z) | ...]
graphTriangles :: Graph -> [(Int, Int, Int)]
graphTriangles (n, g) = [t | t <- allTriangles n, isGraphTriangle t]
where isGraphTriangle (x, y, z) = ...
Таким образом, вы можете потенциально использовать allTriangles
для чего-то другого. Если вы не чувствуете в этом необходимости, вы можете придерживаться единого понимания triangles
, так как это домашнее задание, которое вы, вероятно, не будете развивать на этом.
Я стараюсь не заполнять все ...
, чтобы вы могли сделать это самостоятельно и, надеюсь, поняли:)
Исправление вашего решения:
Во-первых, моя ошибка в диапазонах, это должно быть x <- [1..n], y <- [x+1..n], z <- [y+1..n]
, где n
обозначает количество узлов в вашем графике. Таким образом, вы снимаете только тройки, где x < y < z
, что гарантирует, что вы видите только один случай каждого набора из трех точек.
Во-вторых, причина, по которой я помещаю график в качестве параметра для функций, заключается в том, что вы можете использовать эту же функцию для другого графика. Путем жесткого кодирования g
и 6
в ваших функциях вы делаете их действительно специфичными для конкретного графика, который вы описали, но если вы хотите вычислить triangles
для определенного числа графиков, вы не хотите писать одну функцию на граф!