Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Создаём застёжку для нашей файловой системы

Поиск

Теперь, когда у нас есть файло- вая система, всё, что нам нуж- но, – это застёжка, чтобы мы могли застёгивать файловую систему и брать её крупным пла- ном, а также добавлять, изме- нять и удалять файлы и каталоги. Как и в случае с использовани- ем бинарных деревьев и спис- ков, наши «хлебные крошки» будут содержать информацию обо всём, что мы решили не посещать. Отдельная «хлебная крошка» должна хранить всё, кроме поддерева, на котором

мы фокусируемся в данный момент. Она также должна указывать, где находится отверстие, чтобы при перемещении обратно вверх мы смогли вставить в отверстие наш предыдущий фокус.

В этом случае «хлебная крошка» должна быть похожа на ката- лог – только выбранный нами в данный момент каталог должен в нём отсутствовать. Вы спросите: «А почему не на файл?» Ну, пото- му что, когда мы фокусируемся на файле, мы не можем углубляться в файловую систему, а значит, не имеет смысла оставлять «хлебную крошку», которая говорит, что мы пришли из файла. Файл – это что-то вроде пустого дерева.

Если мы фокусируемся на каталоге "root", а затем на файле "dijon_poupon.doc", как должна выглядеть «хлебная крошка», кото- рую мы оставляем? Она должна содержать имя своего родитель- ского каталога вместе с элементами, идущими перед файлом, на котором мы фокусируемся, и следом за ним. Поэтому всё, что нам


 

требуется, – значение Name и два списка элементов. Храня два отде- льных списка для элементов, идущих перед элементом, на котором мы фокусируемся, и для элементов, идущих за ним, мы будем точно знать, где мы его поместили, при перемещении обратно вверх. Та- ким образом, нам известно местоположение отверстия.

 
 

Вот наш тип «хлебной крошки» для файловой системы:

data FSCrumb = FSCrumb Name [FSItem] [FSItem] deriving (Show)

 
 

А вот синоним типа для нашей застёжки:

type FSZipper = (FSItem, [FSCrumb])

 
 

Идти обратно вверх по иерархии очень просто. Мы берём самую последнюю «хлебную крошку» и собираем новый фокус из текущего фокуса и «хлебной крошки» следующим образом:

fsUp:: FSZipper –> FSZipper

 
 

fsUp (item, FSCrumb name ls rs:bs) = (Folder name (ls ++ [item] ++ rs), bs)

Поскольку нашей «хлебной крошке» были известны имя роди- тельского каталога, а также элементы, которые шли перед находя- щимся в фокусе элементом каталога (то есть ls), и элементы, кото- рые шли за ним (то есть rs), перемещаться вверх было легко.

 
 

Как насчёт продвижения вглубь файловой системы? Если мы на- ходимся в "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" "шмяк!!"

 



Поделиться:


Последнее изменение этой страницы: 2017-02-17; просмотров: 208; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.119.117.77 (0.007 с.)