这是关于Haskell风格的问题。
作为教程示例,我创建了一个支持undo
和redo
操作的小程序。它使用具有两个堆栈的数据结构。
data History a = History [a] [a]
第一个堆栈是游戏的历史。第二个堆栈存储由undo
弹出的状态。所以
undo (History (x:xs) redoStack) = History xs (x:redoStack)
undo history = history -- in case there is nothing to undo
和
redo (History hStack (x:redoStack)) = History (x:hStack) redoStack
redo history = history -- in case there is nothing to redo
还有一个将更改应用于当前状态的通用操作。
applyAChange change (History (x:xs) _) = History ((change x):x:xs) []
applyAChange
的类型是
applyAChange :: (a -> a) -> History a -> History a
我决定定义Change
类型:
type Change a = a -> a
然后applyAChange
的类型变为
applyAChange :: Change a -> Change (History a)
这似乎很有用,我在代码中的其他地方使用了Change
类型。
在定义String
实例时,我发现自己定义了许多类型的函数,如:
convertASomethingToString :: Something -> String
所以我定义了ToString
类型
type ToString a = a -> String
这允许我用类型
编写前面的函数convertASomethingToString :: ToString <Something>
所有这一切似乎都很好,使代码更具信息性。我的问题是
感谢。
答案 0 :(得分:2)
如前所述,您可以使用Endo a
中的Data.Monoid
newtype而不是Change
类型别名。有时处理包装/展开可能是不方便的。但是如果你想要可组合的更改,你可以在它的Monoid
实例中找到有用的东西。
关于您的History
数据类型:在Haskell世界中,它是众所周知的ListZipper
。你可以在不同的地方阅读这个概念。但是在您的代码中,您已经可以在hackage上使用现有的包:http://hackage.haskell.org/package/ListZipper
它有你的功能和其他一些你可能会发现有用的功能。
ToString
类型别名基本上是一种show
函数,没有Show
约束。我不知道如何在没有String
类型绑定的情况下将通用内容转换为Show
,但如果不查看代码,我就不能说更多内容。所以,我的观点是,你基本上不需要ToString
类型别名。最好使用标准函数和类型类。