我目前正在将一些代码从传统的Scala移植到Scalaz样式。
在我的大多数代码中,在我公开的API签名中使用Seq特征而不是直接使用具体类型(即List,Vector)是相当常见的。但是,这给Scalaz带来了一些问题,因为它没有提供Bind [Seq]类型类的实现。
即。这将正常工作。
List(1,2,3,4) >>= bindOperation
但这不会
Seq(1,2,3,4) >>= bindOperation
失败并显示错误could not find implicit value for parameter F0: scalaz.Bind[Seq]
我认为这是Scalaz中的故意设计决定 - 但我不确定如何在此之前进行预期/最佳实践。
我是否应该将代码直接写入List / Vector而不是使用更灵活的Seq接口?或者我应该简单地定义我自己的Bind [Seq]类型类?
答案 0 :(得分:11)
集合库执行后空翻以适应子类型:当您对特定集合类型(列表,映射等)使用map
时,您(通常)会返回相同的类型。它通过使用an extremely complex inheritance hierarchy和CanBuildFrom
等类型类来管理这一点。它完成了工作(至少可以说是有争议的),但复杂性并不是很有原则性。一团糟。很多人讨厌它。
作为图书馆用户,复杂性通常很容易避免,但对于图书馆设计师来说,这是一场噩梦。如果我为Seq
提供monad实例,则意味着我的所有用户类型都会将层次结构提升到Seq
他们使用monadic操作的每种类型。
List
,Vector
等等。你可以看到对此的一些讨论例如,决定on the mailing list。
当我第一次开始使用Scalaz时,我写了很多实用程序代码,试图为Seq
等提供实例,并使它们可以与CanBuildFrom
一起使用。然后我停了下来,现在我倾向于在我自己的代码中使用List
,Vector
,Map
和Set
跟随Scalaz。如果你致力于“Scalaz风格”,你也应该这样做(或者甚至采用Scalaz自己的IList
,ISet
,==>>
等等。但是,你不会更普遍地就最佳实践找到明确的一致意见,并且这两种方法都可以起作用,所以你只需要尝试找到你喜欢的方法。