Haskell Zipper

Haskell Zipper

二叉树

记录方向

二元树

data Tree a = Empty | Node a (Tree a) (Tree a)

改变节点值

data Direction = L | R

change :: [Direction] -> Tree Char -> Tree Char
change (L:xs) (Node x l r) = Node x (change xs l) r
change (R:xs) (Node x l r) = Node x l (change xs r)
change [] (Node _ l r) = Node 'P' l r

查看节点值

elemAt :: [Direction] -> Tree a -> a
elemAt (L:xs) (Node _ l _) = elemAt xs l
elemAt (R:xs) (Node _ _ r) = elemAt xs r
elemAt [] (Node x _ _) = x

示例

elemAt [R, L] $ change [R, L] testTree
= 'P'

行动函数

向右向左行动后, 动作(面包屑)前插在 List

goLeft :: (Tree a, [Direction]) -> (Tree a, [Direction])
goLeft (Node _ l _, xs) = (l, L:xs)
goRight :: (Tree a, [Direction]) -> (Tree a, [Direction])
goRight (Node _ _ r, xs) = (r, R:xs)

逻辑函数

goLeft (goRight (testTree, []))
= (..., [L,R])

定义 -:

(-:) :: a -> (a -> b) -> b
x -: f = f x
(testTree, []) -: goRight -: goLeft
= (..., [L,R])

重定义记录

类型

data Crumb a = LeftCrumb a (Tree a) | RightCrumb a (Tree a)
  • LeftCrumb 左方向 RightCrumb 右方向
  • a 节点值
  • Tree a 未走方向的子树

goLeft

goLeft :: (Tree a, [Crumb a]) -> (Tree a, [Crumb a])
goLeft (Node x l r, xs) = (l, LeftCrumb x r : xs)

goRight

goRight :: (Tree a, [Crumb a]) -> (Tree a, [Crumb a])
goRight (Node x l r, xs) = (r, RightCrumb x l : xs) 

goUp

goUp :: (Tree a, [Crumb a]) -> (Tree a, [Crumb a])
goUp (t, LeftCrumb x r : xs) = (Node x t r, xs)
goUp (t, RightCrumb x l : xs) = (Node x l t, xs)

Zipper

类型

type Zipper a = (Tree a, [Crumb a])

goLeft

goLeft :: Zipper a -> Zipper a
goLeft (Node x l r, xs) = (l, LeftCrumb x r : xs)

goRight

goLeft :: Zipper a -> Zipper a
goLeft (Node x l r, xs) = (r, RightCrumb x l : xs)

goUp

goUp :: Zipper a -> Zipper a
goUp (t, LeftCrumb x r : xs) = (Node x t r, xs)
goUp (t, RightCrumb x l : xs) = (Node x l t, xs)

modify

modify :: (a -> a) -> Zipper a -> Zipper a
modify f (Node x l r, xs) = (Node (f x) l r, xs)
modify f (Empty, xs) = (Empty, xs)
(testTree, []) -: goLeft -: goRight -: modify (\_ -> 'P')

attach

attach :: Tree a -> Zipper a -> Zipper a
attach t (_, xs) = (t, xs)

示例

t1 = (testTree, []) -: goLeft -: goLeft -: goLeft -: goLeft
t2 = t1 -: attach (Node 'Z' Empty Empty)

goTop

goTop :: Zipper a -> Zipper a
goTop (t, []) = (t, [])
goTop z = goTop (goUp z)

List

类型

data List a = Empty | Cons a (List a)
type ListZipper a = ([a], [a])

goForward

goForward :: ListZipper a -> ListZipper a
goForward (x:xs, bs) = (xs, x:bs)

goBack

goBack :: ListZipper a -> ListZipper a
goBack (xs, b:bs) = (b:xs, bs)

示例

xs = [1, 2, 3, 4]
goForward (xs, []) = ([2, 3, 4], [1])

goForward ([2, 3, 4], [1]) = ([3, 4], [2, 1])

goForward ([3, 4], [2, 1]) = ([4], [3, 2, 1])

goBack ([4], [3, 2, 1]) = ([3, 4], [2, 1])

文件系统

类型

type Name = String
type Data = String
data FSItem = File Name Data | Folder Name [FSItem]

Zipper

type FSZipper = (FSItem, [(Name, [FSItem], [FSItem])])

goUp

goUp :: FSZipper -> FSZipper
goUp (item, (name, ls, rs) : bs) = (Folder name (ls ++ [item] ++ rs), bs)

goTo

import Data.List (break)

goTo :: Name -> FSZipper -> FSZipper
goTo name (Folder folderName items, bs) =
	let (ls, item:rs) = break (nameIs name) items
	in (item, (folderName, ls, rs) : bs)
	
nameIs :: Name -> FSItem -> Bool
nameIs name (Folder folderName _) = name == folderName
nameIs name (File fileName _) = name == fileName

示例

t1 = (myDisk, []) -: goTo "f1" -: goTo "e.bmp"

fst t1 = File "e.bmp" "Yikes!"
t2 = t1 -: goUp -: goTo "d.gif"

fst t2 = File "d.gif" "smash!!"
myDisk :: FSItem  
    myDisk = 
        Folder "root"   
            [ File "a.wmv" "baaaaaa"  
            , File "b.avi" "god bless"  
            , Folder "f1"  
                [ File "c.jpg" "bleargh"  
                , File "d.gif" "smash!!"  
                , File "e.bmp" "Yikes!"  
                ]  
            , File "f.doc" "best mustard"  
            , Folder "f2"  
                [ File "g.exe" "10gotofart"  
                , File "h.dmg" "mov eax, h00t"  
                , File "i.exe" "really not a virus"  
                , Folder "f3"  
                    [ File "j.hs" "main = print (fix error)"  
                    , File "k.hs" "main = print 4"  
                    ]  
                ]  
            ]

fsRename

fsRename :: Name -> FSZipper ->FSZipper
fsRename name (Folder _ items, bs) = (Folder name items, bs)
fsRename name (File _ items, bs) = (File name items, bs)

示例

(myDisk, []) -: goTo "f1" -: fsRename "1f" -: goUp

fsNewFile

fsNewFile :: FSItem -> FSZipper -> FSZipper
fsNewFile item (Folder name items, bs) = (Folder name (item:items), bs)

示例

(myDisk, []) -: goTo "f1" -: fsNewFile (File "l.jpg" "lol") -: goUp

Maybe Zipper

goLeft

goLeft :: Zipper a -> Maybe (Zipper a)
goLeft (Node x l r, bs) = Just (l, LeftCrumb x r : bs)
goLeft (Empty, _) = Nothing

goRight

goRight :: Zipper a -> Maybe (Zipper a)
goRight (Node x l r, bs) = Just (r, RightCrumb x l : bs)
goRight (Empty, _) = Nothing

goUp

goUp :: Zipper a -> Maybe (Zipper a)
goUp (t, LeftCrumb x r : bs) = Just (Node x t r, bs)
goUp (t, RightCrumb x l : bs) = Just (Node x l t, bs)
goUp (_, []) = Nothing

示例

testTree = Node 1 Empty (Node 2 Empty Empty)

return (testTree, []) >>= goRight
Just (Node 2 Empty Empty,[RightCrumb 1 Empty])

return (testTree,[]) >>= goRight >>= goRight
Just (Empty,[RightCrumb 2 Empty,RightCrumb 1 Empty])

return (testTree,[]) >>= goRight >>= goRight >>= goRight
Nothing
posted @ 2025-05-08 23:53  (.)$(.)  阅读(7)  评论(0)    收藏  举报