당신이 Option[T]
을 가지고 T
에 대한 Monoid
이 있다면, 다음있을 경우 Monoid[Option[T]]
: 당신이 장착되면
implicit def optionTIsMonoid[T : Monoid]: Monoid[Option[T]] = new Monoid[Option[T]] {
val monoid = implicitly[Monoid[T]]
val zero = None
def append(o1: Option[T], o2: =>Option[T]) = (o1, o2) match {
case (Some(a), Some(b)) => Some(monoid.append(a, b))
case (Some(a), _) => o1
case (_, Some(b)) => o2
case _ => zero
}
}
, 당신은 할 수 sum
(@missingfaktor에서 제안한대로 foldMap(identity)
이상)을 사용하십시오.
List(Some(1), None, Some(2), Some(3), None).asMA.sum === Some(6)
UPDATE
우리는 실제로 위의 코드를 단순화하기 위해 applicatives를 사용할 수 있습니다
implicit def optionTIsMonoid[T : Monoid]: Monoid[Option[T]] = new Monoid[Option[T]] {
val monoid = implicitly[Monoid[T]]
val zero = None
def append(o1: Option[T], o2: =>Option[T]) = (o1 |@| o2)(monoid.append(_, _))
}
날 우리는 어쩌면에 더 일반화 수 있다고 생각한다 : 그런
implicit def applicativeOfMonoidIsMonoid[F[_] : Applicative, T : Monoid]: Monoid[F[T]] =
new Monoid[F[T]] {
val applic = implicitly[Applicative[F]]
val monoid = implicitly[Monoid[T]]
val zero = applic.point(monoid.zero)
def append(o1: F[T], o2: =>F[T]) = (o1 |@| o2)(monoid.append(_, _))
}
을 목록의 목록, 나무 목록을 합칠 수 있습니다.
UPDATE2
문제의 설명은 나를 UPDATE 위 잘못되었음을 깨닫게!입력리스트에서 None
을 거기로 두번째 빨리 None
를 리턴하면서 제 정의 None
값을 이동하기 때문에 리팩토링 모든 optionTIsMonoid
의
먼저, 첫 번째 정의 동등하지 않다. 하지만이 경우에는 Monoid
이 아닙니다! 실제로 Monoid[T]
은 Monoid 법칙을 준수해야하며 zero
은 identity 요소 여야합니다.
zero |+| Some(a) = Some(a)
Some(a) |+| zero = Some(a)
을하지만 Option
의 Applicative
를 사용하여 Monoid[Option[T]]
에 대한 정의를 제안 할 때, 이러한 경우가 있었다 :
우리가해야
None |+| Some(a) = None
None |+| None = None
=> zero |+| a != a
Some(a) |+| None = zero
None |+| None = zero
=> a |+| zero != a
수정하는 것은 우리는 어렵지 않다 zero
의 정의를 변경해야합니다.
// the definition is renamed for clarity
implicit def optionTIsFailFastMonoid[T : Monoid]: Monoid[Option[T]] =
new Monoid[Option[T]] {
monoid = implicitly[Monoid[T]]
val zero = Some(monoid.zero)
append(o1: Option[T], o2: =>Option[T]) = (o1 |@| o2)(monoid.append(_, _))
}
신원 법이 확인 증명
Some(0) |+| Some(i) = Some(i)
Some(0) |+| None = None
=> zero |+| a = a
Some(i) |+| Some(0) = Some(i)
None |+| Some(0) = None
=> a |+| zero = zero
은 (우리는 또한 ...을 associative 법이 존중되고 있는지 확인해야합니다) :이 경우 691,363,210
우리는 (Int
로 T
로)해야합니다.
이제 우리는리스트를 요약 할 때 원하는대로 동작 할 수있는 Monoid[Option[T]]
을 가지고 있습니다 : None
을 건너 뛰거나 "빠름".
안녕하세요 마누엘! 예. 매우 중요한 부분은 항상 처리 방법입니다. 없음 : 무시하거나 실패하면 관련 예제를 참조하십시오. https://gist.github.com/970717 – AndreasScheinert
안녕하세요 Andreas. 너 같은 코드 조각이 내가 필요한거야. –