我认为PartialFunction可以是Monoid。我的思维过程是否正确? 例如,
import scalaz._
import scala.{PartialFunction => -->}
implicit def partialFunctionSemigroup[A,B]:Semigroup[A-->B] = new Semigroup[A-->B]{
def append(s1: A-->B, s2: => A-->B): A-->B = s1.orElse(s2)
}
implicit def partialFunctionZero[A,B]:Zero[A-->B] = new Zero[A-->B]{
val zero = new (A-->B){
def isDefinedAt(a:A) = false
def apply(a:A) = sys.error("error")
}
}
但当前版本的Scalaz(6.0.4)不包括在内。没有包含某些东西的原因是什么?
答案 0 :(得分:28)
让我们对此有不同的看法。
PartialFunction[A, B]
与A => Option[B]
同构。 (实际上,为了能够在不触发对A
的评估的情况下检查是否为给定的B
定义了它,您需要A => LazyOption[B]
)
因此,如果我们能找到Monoid[A => Option[B]]
,我们就证明了你的断言。
鉴于Monoid[Z]
,我们可以按以下方式形成Monoid[A => Z]
:
implicit def readerMonoid[Z: Monoid] = new Monoid[A => Z] {
def zero = (a: A) => Monoid[Z].zero
def append(f1: A => Z, f2: => A => Z) = (a: A) => Monoid[Z].append(f1(a), f2(a))
}
那么,如果我们使用Option[B]
作为我们的Z
,我们会得到什么样的Monoid? Scalaz提供三个。主实例需要Semigroup[B]
。
implicit def optionMonoid[B: Semigroup] = new Monoid[Option[B]] {
def zero = None
def append(o1: Option[B], o2: => Option[B]) = o1 match {
case Some(b1) => o2 match {
case Some(b2) => Some(Semigroup[B].append(b1, b2)))
case None => Some(b1)
case None => o2 match {
case Some(b2) => Some(b2)
case None => None
}
}
}
使用此:
scala> Monoid[Option[Int]].append(Some(1), Some(2))
res9: Option[Int] = Some(3)
但这不是组合两个选项的唯一方法。我们可以简单地选择两者中的第一个或最后一个,而不是在它们都是Some
的情况下附加两个选项的内容。两个触发它,我们创建一个带有标记类型的技巧的独特类型。这与Haskell的newtype
精神相似。
scala> import Tags._
import Tags._
scala> Monoid[Option[Int] @@ First].append(Tag(Some(1)), Tag(Some(2)))
res10: scalaz.package.@@[Option[Int],scalaz.Tags.First] = Some(1)
scala> Monoid[Option[Int] @@ Last].append(Tag(Some(1)), Tag(Some(2)))
res11: scalaz.package.@@[Option[Int],scalaz.Tags.Last] = Some(2)
Option[A] @@ First
,通过它Monoid
附加,使用与您的示例相同的orElse
语义。
所以,把这一切放在一起:
scala> Monoid[A => Option[B] @@ First]
res12: scalaz.Monoid[A => scalaz.package.@@[Option[B],scalaz.Tags.First]] =
scalaz.std.FunctionInstances0$$anon$13@7e71732c
答案 1 :(得分:2)
不,这看起来不错,满足(非交换)Monoid的要求。有趣的想法。您试图支持哪种用例?
答案 2 :(得分:0)
你的零肯定违反了身份元素的公理,但我认为身份(部分)功能可以。
您的附加内容也不符合Monoid法律,但您可以调用 andThen (组合)代替或Else 。但这只适用于A == B:
implicit def partialFunctionSemigroup[A]: Semigroup[A --> A] = new Semigroup[A --> A] {
def append(s1: A --> A, s2: => A --> A): A-->A = s1 andThen s2
}
implicit def partialFunctionZero[A]: Zero[A --> A] = new Zero[A --> A] {
val zero = new (A --> A) {
def isDefinedAt(a:A) = true
def apply(a:A) = a
}
}