对Zipper使用不同类型的当前元素和左/右列表的方法

时间:2012-09-14 16:16:49

标签: class haskell zipper

我正在玩拉链,其中当前元素的类型可能与左右列表不同:

data Z a b = Z ([a], b, [a])

可以使用moveLeftmoveRight导航拉链:

moveLeft  :: (b -> a -> a) -> (a -> b -> b) -> Z a b -> Z a b
moveLeft listF currentF (Z (x:xs, c, ys)) = Z (xs, g x c, ((f c x):ys))

moveRight :: (b -> a -> a) -> (a -> b -> b) -> Z a b -> Z a b
moveRight listF currentF (Z (xs, c, y:ys)) = Z (((f c y):xs), g y c, ys)

在这里,listF将列表元素和当前列表元素转换为左侧或右侧的列表元素。 currentF将当前元素和列表元素转换为当前元素。

如果当前和列表类型都相同,则移动很简单:

moveLeftSameType :: Z a a -> Z a a
moveLeftSameType = moveLeft const const

一切都按预期工作,很好!

我现在要做的是概括上述想法,以便仅为给定的listF实施currentFZ a b函数(例如a :: Char },b :: Int),moveLeftmoveRight自动执行正确的操作。这样做的正确方法是什么?

备注

我试图实现这样的类:

class CPos a where
    listF :: c -> d -> d
    currentF :: d -> c -> c
    moveLeft :: a -> a
    moveRight :: a -> a

其中moveLeft/Right是根据listFcurrentF实施的,但是这会失败

The class method `listF' mentions none of the type variables of the class CPos a

备注2

我一般不喜欢上述观点的事实是允许任意函数listFcurrentF无法保证

moveLeft . moveRight = id

(如果拉链在列表中,则在边框上不支持)。有任何提示要强制执行此操作吗?

1 个答案:

答案 0 :(得分:1)

这是一个解决方案。

class CPos a b where
    listF :: b -> a -> a
    currentF :: a -> b -> b
    moveLeft :: Z a b -> Z a b
    moveLeft (Z (x:xs, c, ys)) = Z (xs, currentF x c, ((listF c x):ys))
    moveRight :: Z a b -> Z a b
    moveRight (Z (xs, c, y:ys)) = Z (((listF c y):xs), currentF y c, ys)

我认为你不能强制执行moveLeft . moveRight = id。我的意思是保证两个功能相等是不可判定的。您可以做的最好的事情就是编写quickcheck个测试用例以保证同样的效果。