簡體   English   中英

Scala PartialFunction可以是Monoid嗎?

[英]Scala PartialFunction can be Monoid?

我認為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)不包括在內。 沒有包含某些東西的原因是什么?

讓我們對此有不同的看法。

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

不,這看起來不錯,滿足(非交換)Monoid的要求。 有趣的想法。 您試圖支持哪些用例?

你的零肯定違反了身份元素的公理,但我認為身份(部分)功能可以。

你的追加也不符合Monoid法律,但你可以調用andEhen (組合)而不是orElse 但這只適用於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
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM