Как насчёт продвижения вглубь файловой системы? Если мы находимся в "root"
"dijon_poupon. doc"
, оставляемая нами «хлебная крошка» будет включать имя "root"
вместе с элементами, предшествующими файлу "dijon_poupon.doc"
, и элементами, идущими за ним. Вот функция, которая, получив имя, фокусируется на файле или каталоге, расположенном в текущем каталоге, куда в текущий момент наведён фокус:import Data.List (break)
fsTo :: Name –> FSZipper –> FSZipper
fsTo name (Folder folderName items, bs) =
let (ls, item:rs) = break (nameIs name) items
in (item, FSCrumb folderName ls rs:bs)
nameIs :: Name –> FSItem –> Bool
nameIs name (Folder folderName _) = name == folderName
nameIs name (File fileName _) = name == fileName
Функция fsTo
Name
и FSZipper
и возвращает новое значение FSZipper
, которое фокусируется на файле с заданным именем. Этот файл должен присутствовать в текущем каталоге, находящемся в фокусе. Данная функция не производит поиск везде – она просто смотрит в текущем каталоге.Сначала мы используем функцию break
break
принимает предикат и список и возвращает пару списков. Первый список в паре содержит элементы, для которых предикат возвращает значение False
. Затем, когда предикат возвращает значение True
для элемента, функция помещает этот элемент и остальную часть списка во второй элемент пары. Мы создали вспомогательную функцию nameIs
, которая принимает имя и элемент файловой системы и, если имена совпадают, возвращает значение True
.Теперь ls
item
является этим самым элементом, а rs
– это список элементов, идущих за ним в его каталоге. И вот сейчас, когда они у нас есть, мы просто представляем элемент, полученный нами из функции break
, как фокус и строим «хлебную крошку», которая содержит все необходимые ей данные.Обратите внимание, что если имя, которое мы ищем, не присутствует в каталоге, образец item:rs
Итак, мы можем двигаться вверх и вниз по нашей файловой системе. Давайте начнём движение с корня и перейдём к файлу "skull_man(scary).bmp"
ghci> let newFocus = (myDisk, []) -: fsTo "pics" -: fsTo "skull_man(scary).bmp"
Значение newFocus
skull_man(scary).bmp
. Давайте получим первый компонент застёжки (сам фокус) и посмотрим, так ли это на самом деле.ghci> fst newFocus
File "skull_man(scary).bmp" "Ой!"
Переместимся выше и сфокусируемся на соседнем с ним файле "watermelon_smash.gif"
ghci> let newFocus2 = newFocus –: fsUp –: fsTo "watermelon_smash.gif"
ghci> fst newFocus2
File "watermelon_smash.gif" "шмяк!!"
Манипулируем файловой системой
Теперь, когда мы можем передвигаться по нашей файловой системе, ею легко манипулировать. Вот функция, которая переименовывает находящийся в данный момент в фокусе файл или каталог:
fsRename :: Name –> FSZipper –> FSZipper
fsRename newName (Folder name items, bs) = (Folder newName items, bs)
fsRename newName (File name dat, bs) = (File newName dat, bs)
Давайте переименуем наш каталог "pics"
"cspi"
:ghci> let newFocus = (myDisk, []) –: fsTo "pics" –: fsRename "cspi" –: fsUp
Мы спустились к каталогу "pics"
Как насчёт функции, которая создаёт новый элемент в текущем каталоге? Встречайте:
fsNewFile :: FSItem –> FSZipper –> FSZipper
fsNewFile item (Folder folderName items, bs) =
(Folder folderName (item:items), bs)