복붙노트

[SCALA] Scalaz 상태 모나드 예

SCALA

Scalaz 상태 모나드 예

나는 scalaz 상태 모나드의 많은 예를 보지 못했다. 이 예는하지만 이해하기 어렵고 보인다 오버 플로우 스택에 다른 하나의 문제가있다.

내가 연주 한 몇 가지 예를 게시거야하지만 난 추가로 사람을 환영합니다. 또한 누군가가 초기화가 넣어 수정하고 좋은 것 그것을 위해 사용됩니다 이유에 대한 예를 제공 할 수 있는지.

편집 : 여기 상태 모나드에 멋진 2 시간 프리젠 테이션입니다.

해결법

  1. ==============================

    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. ==============================

    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. ==============================

    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)))
    

    당신을 수정할 사용할 때 그래서 개념적으로 얻을 넣어 사용하거나 혼자 사용할 수 있습니다.

  4. from https://stackoverflow.com/questions/7734756/scalaz-state-monad-examples by cc-by-sa and MIT license