Я представил трехмерную координату кортежем типа (Int, Int, Int)
Чтобы получить непосредственных соседей координаты, я сделал что-то вроде этого:
neighbours (x,y,z) =
[(x',y',z') | x' <- [(x-1)..(x+1)], y' <- [(y-1)..(y+1)], z' <- [(z-1)..(z+1)], (x,y,z) /= (x',y',z')]
Теперь мне также нужно использовать 4D-координаты, я мог бы сделать что-то очень похожее, чтобы получить соседей с кортежем из 4 элементов, и это сработало бы. Но мне нужно будет продублировать все функции, которые я сделал для 3D-координат, на этот раз для 4D-координат.
Чтобы избежать этого, я подумал о том, чтобы в основном заменить кортежи списком Int, теперь для 3D-координаты это будет, например, [9, 3, 0] и 4D-координата [5, 1, 0, 1] и так далее.
Как я могу получить соседей с массивом Int? Я пытался использовать понимание списка, но мне не удалось найти решение.
PS: я новичок в Haskell и функциональном программировании.
Вы можете продолжить рекурсивно и реализовать (N+1)-D соседей с точки зрения N-D соседей.
По сути, если у вас есть точка (N+1)-D [x1,...,xNplus1], она имеет форму x1 : xs, где xs — точка N-D. Итак, если вы уже знаете список соседей xs, вы можете превратить его в список соседей x1 : xs.
Вот простая попытка, которая должна почти сработать.
almostNeighbours :: [Int] -> [[Int]]
almostNeighbours [] = [[]]
almostNeighbours (x:xs) =
[ x' : xs'
| x' <- [x-1 .. x+1] , xs' <- almostNeighbours xs ]
Обратите внимание, что мы включаем саму точку в список соседей. В противном случае в рекурсивном случае не будет получено достаточного количества точек. (Я рекомендую убедить себя, что это действительно так.)
Если вам не нужна сама точка, вы всегда можете удалить ее позже с помощью дополнительной функции, не влияя на рекурсивное определение.
Наконец, обратите внимание, что приведенный выше код, вероятно, не будет таким же быстрым, как исходный, поскольку доступ к спискам медленнее, чем к кортежам.
Небольшая альтернатива: используя аппликативный стиль, мы можем немного сократить код.
almostNeighbours :: [Int] -> [[Int]]
almostNeighbours [] = pure []
almostNeighbours (x:xs) = (:) <$> [x-1 .. x+1] <*> almostNeighbours xs
Большое спасибо, это именно то, что я искал, и теперь, когда я это вижу, это имеет смысл. Это обязательно запомнят. Не могу отблагодарить вас достаточно!
Дублировать будет намного меньше, если вы реализуете это как neighbors (x,y,z) = delete (x,y,z) $ range ((x-1, y-1, z-1), (x+1, y+1, z+1)).