Лучший способ написать глубокие карты в Haskell? - PullRequest
2 голосов
/ 09 марта 2020

Я анализирую текстовый файл, содержащий строки чисел. Я хочу превратить их в [[[Int]]]. (Список ячеек внутри списка строк внутри списка досок.)

sudoku.txt

530070000
600195000
098000060
800060003
400803001
700020006
060000280
000419005
000080079

400700500
300800001
700900008
060030010
090070050
080010790
002006900
005000030
000004200
...

main.hs

parseTextExample :: IO ()
parseTextExample = do
  handle <- openFile "sudoku.txt" ReadMode
  contents <- hGetContents handle
  let splitBoards = splitWhen (== "") $ lines contents
  let sudokus = map (\board -> map (\row -> map (\char -> read [char] :: Int) row) board) splitBoards
  print sudokus
  hClose handle

splitBoards дает [[String]], и я хочу использовать sudokus для получения [[[Int]]]. Это требует глубокого отображения, которое выглядит ужасно:

map (\board -> map (\row -> map (\char -> read [char] :: Int) row) board) splitBoards

Есть ли более хаскеллианский способ написания функции sudokus?


Для справки:

> print splitBoards
>[["530070000","600195000","098000060","800060003","400803001","700020006","060000280","000419005","000080079"],["400700500","300800001","700900008","060030010","090070050","080010790","002006900","005000030","000004200"]]
> print sudokus
>
[[[5,3,0,0,7,0,0,0,0],[6,0,0,1,9,5,0,0,0],[0,9,8,0,0,0,0,6,0],[8,0,0,0,6,0,0,0,3],[4,0,0,8,0,3,0,0,1],[7,0,0,0,2,0,0,0,6],[0,6,0,0,0,0,2,8,0],[0,0,0,4,1,9,0,0,5],[0,0,0,0,8,0,0,7,9]],[[4,0,0,7,0,0,5,0,0],[3,0,0,8,0,0,0,0,1],[7,0,0,9,0,0,0,0,8],[0,6,0,0,3,0,0,1,0],[0,9,0,0,7,0,0,5,0],[0,8,0,0,1,0,7,9,0],[0,0,2,0,0,6,9,0,0],[0,0,5,0,0,0,0,3,0],[0,0,0,0,0,4,2,0,0]]]

1 Ответ

6 голосов
/ 09 марта 2020

Вы можете заключить значение в список, используя pure :: Applicative f => a -> f a, поэтому мы можем записать \char -> read [char], как read . pure.

Далее мы можем записать \row -> map (read . pure) row лямбда-выражение как map (read . pure). Таким образом, это означает, что мы можем переписать строку следующим образом:

let sudokus = map (map (map (read . pure))) splitBoards :: [[[Int]]]

или мы можем избежать этих скобок с помощью:

let sudokus = (<b>map . map . map</b>) (read . pure) splitBoards :: [[[Int]]]

Здесь это означает, что (read . pure) является функцией отображения из "самого внутреннего" map.

...