2015-11-29 3 views
4

Я пытаюсь совместить Reader монада с монахом State. Вот мой код:Как объединить читатель и государственную монаду

object StatePoc extends App { 
    def startsWithState : Reader[String, State[Seq[String], Unit]] = Reader { s => State { ss => (ss.filter(_.startsWith(s)), Unit)}} 
    def endsWithState : Reader[String, State[Seq[String], Unit]] = Reader { s => State { ss => (ss.filter(_.endsWith(s)), Unit)}} 
    def process: Kleisli[Id.Id, String, State[Seq[String], Unit]] = { 
    for { 
     s <- startsWithState 
     e <- endsWithState 
    } yield e 
    } 

    val all = Seq("AB", "BA", "ABA", "ABBA") 

    println(process("A")(all)) 
} 

К сожалению, этот код не возвращает ожидаемый результат: List(BA, ABA, ABBA) вместо List(ABA, ABBA).

ответ

4

В вашей функции process вы читаете объект состояния у обоих своих читателей, но вы просто возвращаете последний объект состояния, а не комбинацию из двух. Нечто подобное было бы объединить оба s и e:

def process: Kleisli[Id.Id, String, State[Seq[String], Unit]] = { 
    for { 
     s <- startsWithState 
     e <- endsWithState 
    } yield { 
     State { seq => e.run(s.run(seq)._1)} 
    } 
    } 
+0

Спасибо. Использование вложенного для улучшения компа также процесса DEF = {{ для с <- startsWithState х <- endsWithState } {выходом для _ <- х сс <- с } выход сс } –

2

Другой спаситель может быть монада трансформатор, который требует шаблонного, особенно без любезного-проектор:

type StringReader[a] = Reader[String, a] 
type StateChoose[a, b] = StateT[StringReader, a, b] 
type StringsChoose[a] = StateChoose[Seq[String], a] 
type StringsTrans[m[_], b] = StateT[m, Seq[String], b] 

def ST = MonadState[StateChoose, Seq[String]] 
def R = MonadReader[Reader, String] 
def T = MonadTrans[StringsTrans] 

def transform(action: String => Seq[String] => Seq[String]): StringsChoose[Unit] = for { 
    s <- T.liftMU(R.ask) 
    _ <- ST.modify(action(s)) 
} yield() 
def startsWithState = transform(s => _.filter(_.startsWith(s))) 
def endsWithState = transform(s => _.filter(_.endsWith(s))) 

def process: StringsChoose[Unit] = { 
    for { 
    s <- startsWithState 
    e <- endsWithState 
    } yield e 
} 
val all = Seq("AB", "BA", "ABA", "ABBA") 

println(process.exec(all).apply("A")) 
Смежные вопросы