Предположим, что у меня есть некоторые данные, которые организованы в виде сетки, как это (размеры могут варьироваться, но сторона сетки всегда n**2
):Haskell: создавать различные представления для тех же данных
0 1 2 3
4 5 6 7
8 9 A B
C D E F
Что я хотел бы добиться того, чтобы иметь список с теми же данными, представленными различными способами, т.е. разбить на колонки, строки, или (что самое главное) клетки, который
0 1 | 2 3
4 5 | 6 7
----+----
8 9 | A B
C D | E F
Так что, если я какое-то действие, я буду в состоянии получить данные в виде следующего списка:
[[0, 1, 4, 5],
[2, 3, 6, 7],
[8, 9, C, D],
[A, B, E, F]]
Если заказ не имеет значения.
Я хотел бы использовать это, чтобы позже построить объектив, который сможет устанавливать значения с учетом различных видов представлений. Это то, что могло бы быть достигнуто с использованием указателей или ссылок на императивных языках (где это применимо).
Помимо особенностей, я хотел бы знать, существует ли общий подход к представлению одинаковых внутренних данных по-разному.
Вот что я до сих пор, используя [Int]
в качестве внутреннего представления и функции преобразования, чтобы получить конкретные «мнения»:
import Data.List (transpose)
data Access = Rows | Columns | Cells
isqrt :: Int -> Int
isqrt = floor . sqrt . fromIntegral
group :: Int -> [a] -> [[a]]
group _ [] = []
group n l
| n > 0 = (take n l) : (group n (drop n l))
| otherwise = error "inappropriate n"
representAs :: [Int] -> Access -> [[Int]]
representAs list Rows = group (isqrt . length $ list) list
representAs list Columns = transpose $ list `representAs` Rows
representAs list Cells = let row_width = isqrt . length $ list
cell_width = isqrt row_width
drops = map (\x -> cell_width
* row_width
* (x `quot` cell_width)
+ cell_width
* (x `rem` cell_width)
) [0..row_width-1]
in (map ((map snd)
. (filter ((==0)
. (`quot` cell_width)
. (`rem` row_width)
. fst)
)
. (zip [0..])
. (take (row_width * cell_width))
. (`drop` list)
) drops
)
main = mapM_ (putStrLn . show) ([1..16] `representAs` Cells)
Мой вопрос основан на той же идее, this one, но ответа там считает только проблемы с памятью, а не строительство. Кроме того, если я хочу хранить одни и те же данные по-разному в нескольких представлениях, мне придется обновить их все, установив новое значение, насколько я понимаю.
Я не буду чтобы список представлял это, это будет ужасно неэффективно. Кроме того, вместо того, чтобы показывать данные в разных представлениях, вы действительно должны создать объектив - это позволит вам просматривать и изменять матрицу с различными видами ваших данных без ненужного преобразования. например 'Access -> Lens '(Array (Int, Int) a) (Array Int a)' или 'Access -> Traversal' (Array (Int, Int) a) a' – user2407038
@ user2407038 Я думал, что только создание объектива возможно после того, как я предоставил какой-то сеттер и геттер, например, используя функцию «индекс», предложенную @AlexeyKuleshevich как геттер, и соответствующий сеттер. Можно ли это сделать другим способом? – sukhmel