我正在玩拉链,其中当前元素的类型可能与左右列表不同:
data Z a b = Z ([a], b, [a])
可以使用moveLeft
和moveRight
导航拉链:
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
实施currentF
和Z a b
函数(例如a :: Char
},b :: Int
),moveLeft
和moveRight
自动执行正确的操作。这样做的正确方法是什么?
备注
我试图实现这样的类:
class CPos a where
listF :: c -> d -> d
currentF :: d -> c -> c
moveLeft :: a -> a
moveRight :: a -> a
其中moveLeft/Right
是根据listF
和currentF
实施的,但是这会失败
The class method `listF' mentions none of the type variables of the class CPos a
备注2
我一般不喜欢上述观点的事实是允许任意函数listF
和currentF
无法保证
moveLeft . moveRight = id
(如果拉链在列表中,则在边框上不支持)。有任何提示要强制执行此操作吗?
答案 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
个测试用例以保证同样的效果。