[SCALA] Scalaz 상태 모나드 예
SCALAScalaz 상태 모나드 예
나는 scalaz 상태 모나드의 많은 예를 보지 못했다. 이 예는하지만 이해하기 어렵고 보인다 오버 플로우 스택에 다른 하나의 문제가있다.
내가 연주 한 몇 가지 예를 게시거야하지만 난 추가로 사람을 환영합니다. 또한 누군가가 초기화가 넣어 수정하고 좋은 것 그것을 위해 사용됩니다 이유에 대한 예를 제공 할 수 있는지.
편집 : 여기 상태 모나드에 멋진 2 시간 프리젠 테이션입니다.
해결법
-
==============================
1.나는 scalaz의 7.0.x와 (scalaz 6.x에서 대한 응답 역사를 보면) 다음과 같은 수입을 가정합니다 :
나는 scalaz의 7.0.x와 (scalaz 6.x에서 대한 응답 역사를 보면) 다음과 같은 수입을 가정합니다 :
import scalaz._ import Scalaz._
상태 | S, A]가 S의 상태의 형식이고 A는 장식되는 값의 종류이기 때문에, 상태 유형을 정의한다. 기본 구문 값 차종이 주 사용 상태 [S, A] 함수를 만들려면
// Create a state computation incrementing the state and returning the "str" value val s = State[Int, String](i => (i + 1, "str"))
초기치의 상태 계산을 실행하려면 :
// start with state of 1, pass it to s s.eval(1) // returns result value "str" // same but only retrieve the state s.exec(1) // 2 // get both state and value s(1) // or s.run(1) // (2, "str")
상태는 함수 호출을 통해 스레드 수 있습니다. [A, B] 기능 대신이를 위해 정의 함수 [A, 상태 | S, B]]. 국가 기능을 사용하여 ...
import java.util.Random def dice() = State[Random, Int](r => (r, r.nextInt(6) + 1))
이어서 대 / 수율 구문 작성 기능으로 사용할 수있다 :
def TwoDice() = for { r1 <- dice() r2 <- dice() } yield (r1, r2) // start with a known seed TwoDice().eval(new Random(1L)) // resulting value is (Int, Int) = (4,5)
여기에 또 다른 예이다. TwoDice () 상태 계산으로 목록을 채 웁니다.
val list = List.fill(10)(TwoDice()) // List[scalaz.IndexedStateT[scalaz.Id.Id,Random,Random,(Int, Int)]]
사용 순서는 주 [임의, 목록 [(INT, INT)]를 얻을 수 있습니다. 우리는 유형 별칭을 제공 할 수 있습니다.
type StateRandom[x] = State[Random,x] val list2 = list.sequence[StateRandom, (Int,Int)] // list2: StateRandom[List[(Int, Int)]] = ... // run this computation starting with state new Random(1L) val tenDoubleThrows2 = list2.eval(new Random(1L)) // tenDoubleThrows2 : scalaz.Id.Id[List[(Int, Int)]] = // List((4,5), (2,4), (3,5), (3,5), (5,5), (2,2), (2,4), (1,5), (3,1), (1,6))
아니면 유형을 추론 할 sequenceU을 사용할 수 있습니다 :
val list3 = list.sequenceU val tenDoubleThrows3 = list3.eval(new Random(1L)) // tenDoubleThrows3 : scalaz.Id.Id[List[(Int, Int)]] = // List((4,5), (2,4), (3,5), (3,5), (5,5), (2,2), (2,4), (1,5), (3,1), (1,6))
상태 다른 예 [맵 [INT, 지능, 지능 위에서 목록에 합계 계산 주파수이다. freqSum는 드로우와 주파수 계수의 합을 계산한다.
def freqSum(dice: (Int, Int)) = State[Map[Int,Int], Int]{ freq => val s = dice._1 + dice._2 val tuple = s -> (freq.getOrElse(s, 0) + 1) (freq + tuple, s) }
이제 tenDoubleThrows 이상 freqSum을 적용 트래버스 사용합니다. 트래버스는 (freqSum) .sequence를 매핑하는 것과 동일합니다.
type StateFreq[x] = State[Map[Int,Int],x] // only get the state tenDoubleThrows2.copoint.traverse[StateFreq, Int](freqSum).exec(Map[Int,Int]()) // Map(10 -> 1, 6 -> 3, 9 -> 1, 7 -> 1, 8 -> 2, 4 -> 2) : scalaz.Id.Id[Map[Int,Int]]
또는 더 간결 유형을 추론하는 traverseU를 사용하여 :
tenDoubleThrows2.copoint.traverseU(freqSum).exec(Map[Int,Int]()) // Map(10 -> 1, 6 -> 3, 9 -> 1, 7 -> 1, 8 -> 2, 4 -> 2) : scalaz.Id.Id[Map[Int,Int]]
주 [S, A가] StateT [ID, S, A]에 대한 유형 별칭이기 때문에, tenDoubleThrows2가 끝나는 주 이드로 입력된다. 나는 목록 유형으로 다시 설정하는 copoint를 사용합니다.
단지에 대한 느낌을 얻을려고, 내가 생산 코드에서 상태를 사용한 적이 : 즉, 사용 상태의 핵심은 국가와 실제 결과 값을 수정하는 함수를 리턴하는 함수가 원하는 ... 포기해야 할 것 같다.
@ziggystar 주석에 대한 추가 정보
나는 StateFreq 또는 StateRandom가 결합 된 계산을 수행하기 위해 확장 될 수있는 경우에 다른 사람이 보여줄 수있을 수 있습니다 stateT를 사용하여 시도에 포기했다. 내가 대신 발견 한 것은 두 주 변압기의 구성은 다음과 같이 결합 될 수 있다는 것입니다 :
def stateBicompose[S, T, A, B]( f: State[S, A], g: (A) => State[T, B]) = State[(S,T), B]{ case (s, t) => val (newS, a) = f(s) val (newT, b) = g(a) apply t (newS, newT) -> b }
이는 g는 제 1 상태 변압기의 결과를 측정하고있는 상태 변압기 복귀 한 파라미터의 함수 인 것을 전제. 그런 다음이 작동합니다 :
def diceAndFreqSum = stateBicompose(TwoDice, freqSum) type St2[x] = State[(Random, Map[Int,Int]), x] List.fill(10)(diceAndFreqSum).sequence[St2, Int].exec((new Random(1L), Map[Int,Int]()))
-
==============================
2.나는 모나드 변압기를 통해 두 개의 상태 모나드를 적용의 예를 가지고 sigfp에서 grok 수 하스켈 모나드 트랜스 포머 포스트 흥미로운 블로그에 비틀 거렸다. 여기 scalaz 번역입니다.
나는 모나드 변압기를 통해 두 개의 상태 모나드를 적용의 예를 가지고 sigfp에서 grok 수 하스켈 모나드 트랜스 포머 포스트 흥미로운 블로그에 비틀 거렸다. 여기 scalaz 번역입니다.
제 1 실시 나타내는 상태 | INT, _] 모나드 :
val test1 = for { a <- init[Int] _ <- modify[Int](_ + 1) b <- init[Int] } yield (a, b) val go1 = test1 ! 0 // (Int, Int) = (0,1)
그래서 여기에 초기화를 사용하여 수정의 예를 가지고있다. 그것으로 조금 연주 후, 초기화 [S]는 주 [S, S] 값을 생성 정말 편리한 것으로 판명하지만 수있는 다른 것은 이해의 내부 상태에 액세스 할 수 있습니다. [S]을 수정은 이해를 위해 내부 상태를 전환하기위한 편리한 방법이다. 예 그래서 위와 같이 읽을 수 있습니다 :
이해 구문 이미 주 [A S,]의 A 측에서 작동하도록 사소한한다. 초기화 넣어, 수정 및 주 [S, A]에서 S 측의 작업에 대한 몇 가지 도구를 제공 가져옵니다.
블로그 게시물의 두 번째 예에 번역 :
val test2 = for { a <- init[String] _ <- modify[String](_ + "1") b <- init[String] } yield (a, b) val go2 = test2 ! "0" // (String, String) = ("0","01")
TEST1으로 매우 거의 같은 설명.
세 번째 예는 더 까다 롭습니다 그리고 내가 발견 아직 출시되지 않은 간단한 무언가가 있기를 바랍니다.
type StateString[x] = State[String, x] val test3 = { val stTrans = stateT[StateString, Int, String]{ i => for { _ <- init[String] _ <- modify[String](_ + "1") s <- init[String] } yield (i+1, s) } val initT = stateT[StateString, Int, Int]{ s => (s,s).pure[StateString] } for { b <- stTrans a <- initT } yield (a, b) } val go3 = test3 ! 0 ! "0" // (Int, String) = (1,"01")
그 코드에 stTrans뿐만 아니라 문자열 상태 꺼내 ( "1"로 증가 및 접미사) 양자 상태의 변환을 담당한다. stateT 우리가 상태가 증가되는 int이며이 경우 임의 모나드 M. 상태에서 변형을 추가 할 수있다. 우리는 stTrans라고하면! 0 우리는 M [문자열]로 끝날 것입니다. 우리는 주 [문자열, 문자열]입니다 StateString [문자열]하게 될 겁니다, 그래서 우리의 예에서, M은 StateString입니다.
여기에 까다로운 부분은 우리가 stTrans에서 지능 상태 값을 꺼내 할 것입니다. 이 initT을위한 것입니다. 그것은 단지 우리가 stTrans와 flatMap 할 수있는 방법으로 상태에 대한 접근을 제공하는 개체를 만듭니다.
편집 : 우리가 진정으로 편리하게 자신의 반환 튜플의 _2 요소에 원하는 상태를 저장 시험 1 TEST2를 재사용하는 경우 그 어색함의 모든 밝혀 피할 수 있습니다 :
// same as test3: val test31 = stateT[StateString, Int, (Int, String)]{ i => val (_, a) = test1 ! i for (t <- test2) yield (a, (a, t._2)) }
-
==============================
3.여기에 국가가 사용할 수있는 방법에 대한 아주 작은 예입니다 :
여기에 국가가 사용할 수있는 방법에 대한 아주 작은 예입니다 :
의 일부 게임 유닛 (또한 게임 단위) 보스와 싸우고있는 작은 "게임"을 정의 할 수 있습니다.
case class GameUnit(health: Int) case class Game(score: Int, boss: GameUnit, party: List[GameUnit]) object Game { val init = Game(0, GameUnit(100), List(GameUnit(20), GameUnit(10))) }
우리는 게임의 상태를 추적 할에 플레이하면, 그래서 상태 모나드의 관점에서 우리의 "행동"을 정의 할 수 있습니다 :
그는 자신의 건강에서 10을 잃게 그래서 하드 보스를 공격하자
def strike : State[Game, Unit] = modify[Game] { s => s.copy( boss = s.boss.copy(health = s.boss.health - 10) ) }
그리고 보스가 다시 공격 할 수! 그가하는 때 파티에서 모두 5 건강을 잃는다.
def fireBreath : State[Game, Unit] = modify[Game] { s => val us = s.party .map(u => u.copy(health = u.health - 5)) .filter(_.health > 0) s.copy(party = us) }
이제 우리는 플레이에 이러한 작업을 작성할 수 있습니다 :
def play = for { _ <- strike _ <- fireBreath _ <- fireBreath _ <- strike } yield ()
실제 생활에서 물론 플레이는 더 역동적 수 있지만 내 작은 예를 들어 식품 충분하다 :)
우리는 게임의 최종 상태를보고 지금 실행할 수 있습니다 :
val res = play.exec(Game.init) println(res) >> Game(0,GameUnit(80),List(GameUnit(10)))
우리는 거의 보스를 쳤고 단위 중 하나는 RIP, 사망 한 그래서.
여기서 포인트는 구성이다. 주 (단지 기능을 S => (A, S))는 당신이 생산 결과 그 작업을 정의뿐만 아니라 너무 많은 국가가 어디에서 오는 모르게 어떤 상태를 조작 할 수 있습니다. 당신의 행동이 구성 될 수 있도록 모나드 부분은 당신에게 구성을 제공합니다 :
A => State[S, B] B => State[S, C] ------------------ A => State[S, C]
등등.
추신 GET의 차이에 관해서는, 넣어 수정 :
수정은 GET으로 볼 함께 넣어 수 있습니다 :
def modify[S](f: S => S) : State[S, Unit] = for { s <- get _ <- put(f(s)) } yield ()
또는 단순히
def modify[S](f: S => S) : State[S, Unit] = get[S].flatMap(s => put(f(s)))
당신을 수정할 사용할 때 그래서 개념적으로 얻을 넣어 사용하거나 혼자 사용할 수 있습니다.
from https://stackoverflow.com/questions/7734756/scalaz-state-monad-examples by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 스칼라 파일에서 jar 파일 만들기 (0) | 2019.11.14 |
---|---|
[SCALA] 자원 스칼라 폴더에서 어떻게 파일을 읽을? (0) | 2019.11.14 |
[SCALA] 스칼라 기능적 대하여 반응성 프로그래밍 [폐쇄] (0) | 2019.11.14 |
[SCALA] 스칼라 튜플 풀고 (0) | 2019.11.14 |
[SCALA] 스칼라 - 제네릭의 모든 대 밑줄 (0) | 2019.11.14 |