在Haskell中创建泛型函数类型的集合是否有用

时间:2016-11-03 21:36:40

标签: haskell types

这是关于Haskell风格的问题。

作为教程示例,我创建了一个支持undoredo操作的小程序。它使用具有两个堆栈的数据结构。

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>

所有这一切似乎都很好,使代码更具信息性。我的问题是

  1. 这种事情有多少值得做?
  2. 只要有人这样做,创建一个由这些类型定义组成的模块并导入它是否有意义?这是标准的事吗?
  3. 是否已经有一个广泛使用的这类有用类型的模块?
  4. 感谢。

1 个答案:

答案 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类型别名。最好使用标准函数和类型类。