설명 Traverse[List]구현에 scalaz-seven
-
14-12-2019 - |
문제
려고 노력해요 이해하는 traverseImpl
구현 scalaz-seven:
def traverseImpl[F[_], A, B](l: List[A])(f: A => F[B])(implicit F: Applicative[F]) = {
DList.fromList(l).foldr(F.point(List[B]())) {
(a, fbs) => F.map2(f(a), fbs)(_ :: _)
}
}
할 수 있는 사람이 방법을 설명 List
와 상호 작용 Applicative
?궁극적으로 나가고 싶으로 구현할 수 있는 다른 인스턴스 Traverse
.
해결책
는 실용적 적용할 수 있는 기능이 컨텍스트에서 값으로는 컨텍스트에서.그래서 예를 들어,적용할 수 있습니다 some((i: Int) => i + 1)
하기 some(3)
고 some(4)
.Let's 잊는다.나는 돌아올 것입니다.
목록는 두 가지 표현,그것의 중 Nil
나 head :: tail
.당신이 사용할 수 있습을 통해 배를 사용하여 foldLeft
하지만 다른 방법을 통해 배 it:
def foldr[A, B](l: List[A], acc0: B, f: (A, B) => B): B = l match {
case Nil => acc0
case x :: xs => f(x, foldr(xs, acc0, f))
}
어 List(1, 2)
우리는 겹 이상의 목록을 적용하는 기능에서 시작하여 오른쪽-도록 우리가 정말 해체 목록에서 왼쪽!
f(1, f(2, Nil))
이 사용할 수 있습을의 길이를 계산합니다.어 List(1, 2)
:
foldr(List(1, 2), 0, (i: Int, acc: Int) => 1 + acc)
// returns 2
이 또한 사용할 수 있습니다 성 다른 목록:
foldr[Int, List[Int]](List(1, 2), List[Int](), _ :: _)
//List[Int] = List(1, 2)
그래서 주어진 빈 목록 ::
우리는 기능을 만들 수 있었다는 또 다른 목록입니다.어떤 경우에 우리의 요소들에서 일부 컨텍스트?는 경우 우리의 상황에 맞는 실용적인 그런 다음 우리는 여전히 적용할 수 있는 우리의 요소 ::
그런 맥락에서.계속 List(1, 2)
고 Option
으로 우리의 실용적입니다.우리 시작 some(List[Int]()))
우리는 우리를 원 적용 ::
기능 Option
context.이것은 무엇인 F.map2
는 않습니다.그것은 두 값에서 자신의 Option
컨텍스트를 넣어 제공의 기능을 두 개의 인로 Option
컨텍스트를 적용합니다.
그래서 외부의 컨텍스트리 (2, Nil) => 2 :: Nil
컨텍스트에서 우리는: (Some(2), Some(Nil)) => Some(2 :: Nil)
원래 질문:
// do a foldr
DList.fromList(l).foldr(F.point(List[B]())) {
// starting with an empty list in its applicative context F.point(List[B]())
(a, fbs) => F.map2(f(a), fbs)(_ :: _)
// Apply the `::` function to the two values in the context
}
나는 확실하지 않은 그러한 차이가 나는 이유가 무엇 DList
사용됩니다.내가 보는 것은 그것이 사용하는 트램폴린 그렇게 희망이 구현없이 작동 불가 스택,그러나 나는 아무도 모르겠습니다.
흥미로운 부분을 구현하는 방법에 대한 권리를 접어 이 같은 생각을 접근 구현을 통과를 위해 algebric 를 사용하여 데이터 형식 catamorphisms.
예를 들어:
trait Tree[+A]
object Leaf extends Tree[Nothing]
case class Node[A](a: A, left: Tree[A], right: Tree[A]) extends Tree[A]
배 것 다음과 같이 정의한다(정말 다음과 같은 방법으로 List
):
def fold[A, B](tree: Tree[A], valueForLeaf: B, functionForNode: (A, B, B) => B): B = {
tree match {
case Leaf => valueForLeaf
case Node(a, left, right) => functionForNode(a,
fold(left, valueForLeaf, functionForNode),
fold(right, valueForLeaf, functionForNode)
)
}
}
및 통과 사용하는 fold
가 F.point(Leaf)
적용 Node.apply
.은 없지만 F.map3
그래서 될 수 있습니다.
다른 팁
이지 않는 무언가가 그렇게 이해하기 쉽습니다.추천 기사를 읽 연결의 시작 부분에서 내 블로그 포스팅에서 주제.
나는 또한 프레젠테이션에서 주제 중에 마지막 기능적 프로그래밍 회의 시드니에서 당신을 찾을 수 있습니다 슬라이드 기.
수 있다면 나는 설명하려고 몇 가지 단어를, traverse
가을 통과하는 각 요소의 목록을 하나 하나 결국 다시설 목록 (_ :: _)
하지만 축적/실행하는 어떤 종류의"효과"등에 의해 주어 F Applicative
.는 경우 F
가 State
그것은 유의 일부 상태입니다.는 경우 F
는 실용적인 해당하는 Monoid
그것은 집계 어떤 종류의 측정에 대한 각각의 요소의 목록에 있습니다.
주요 상호 작용의 목록 및 실용적이 map2
어플리케이션 수신 F[B]
요소를 첨부하여 다른 F[List[B]]
요소에 의해 정의 F
로 Applicative
의 사용 List
생성자 ::
특정 기능이 적용됩니다.
거기에서 당신은 참조를 구현하는 기타 인스턴스 Traverse
대만 apply
ing 데이터 생성자를 데이터의 구조는 당신이 원하는 통과합니다.이 있는 경우에 연결된 파워 포인트 프리젠 테이션,당신이 볼 수 일부 슬라이드 트리 바이너리 traversal.
List#foldRight
불어 스택에 대한 큰 목록이 있습니다.이에 복제:
List.range(0, 10000).foldRight(())((a, b) => ())
할 수 있습니다 일반적으로,반대 목록의 사용 foldLeft
, 다음,반대의 결과를 피하는 이 문제를 해결합니다.지 traverse
우리가 정말 프로세스 요소에 올바른 순서로 하는지 확인하 효과로 처리습니다. DList
는 편리한 방법 덕분에,trampolining.
결국,이러한 테스트를 통과해야 합:
https://github.com/scalaz/scalaz/blob/scalaz-seven/tests/src/test/scala/scalaz/TraverseTest.scala#L13 https://github.com/scalaz/scalaz/blob/scalaz-seven/tests/src/test/scala/scalaz/std/ListTest.scala#L11 https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Traverse.scala#L76