Изучай Haskell во имя добра! (Липовача) - страница 290

, которое фокусируется на файле с заданным именем. Этот файл должен присутствовать в текущем каталоге, находящемся в фокусе. Данная функция не производит поиск везде – она просто смотрит в текущем каталоге.



Сначала мы используем функцию >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