2016-12-29 14 views
1

Я учусь монады трансформаторов и есть проблема секвенирования ихScalaz: как совместить монады типа OptionT [государства] [_, T], поэтому оно не будет прекращено на None

Я создал тип OptionTBitSetState[T]

Я понимаю, этот тип как сохраняющее состояние вычислений, которые могут потерпеть неудачу

import scalaz._, Scalaz._ 
import scala.collection.immutable.BitSet 

type BitSetState[T] = State[BitSet, T] 
type OptionTBitSetState[T] = OptionT[BitSetState, T] 
object OptionTBitSetState { 
    def apply[T](option : Option[T]) : OptionT[BitSetState, T] = 
    OptionT[BitSetState, T](State[BitSet, Option[T]](_ -> option)) 

    def apply[T](state : State[BitSet, T]) : OptionT[BitSetState, T] = 
    OptionT[BitSetState, T](state.map(_.some)) 
} 

у меня есть функция шага с подписью

def step(i : Int) : OptionTBitSetState[Seq[Int]] 

Эта функция должна:

  1. Проверьте BitSet внутри государства содержит параметр i
    • Если она не содержит: добавить i к BitSet и вернуть Seq(i, i*10, i*100)
    • Если он содержит : сбой None

Реализация функции шаг:

def step(i : Int) : OptionTBitSetState[Seq[Int]] = 
    for { 
    usedIs <- OptionTBitSetState(get[BitSet]) 
    res <- OptionTBitSetState(
     Some(Seq(i, i*10, i*100)).filterNot(_ => usedIs.contains(i)) 
    ) 
    _ <- OptionTBitSetState(put(usedIs + i)) 
    } yield res 

Я хочу, чтобы упорядочить список шага ы таким образом, что, когда я оцениваю эту последовательность, я получаю список опций в качестве результата. Но подпись sequence отличается. Вместо этого я получаю вариант списков.

например.

List(1,2,1,3).map(step).sequence.run(BitSet.empty) 

возвращается None, но то, что я хочу это:

List(Some(Seq(1, 10, 100)), Some(Seq(2, 20, 200)), None, Some(Seq(3, 30, 300))) 

Есть ли способ, я могу объединить OptionTBitSetState[T] с, так что я получаю поведение мне нужно?

ответ

2

По моему скромному мнению, вы чрезмерно усложняете решение, используя OptionT.

Проблема с OptionT заключается в том, что он хочет рассматривать значение внутри монады как существующее или отсутствующее, поэтому, когда вы «сворачиваете» отдельные вычисления в одно государство для его запуска, любой отдельный сбой должен вызывать всю вещь потерпеть неудачу.

Я бы просто использовал State[BitSet,Option[Seq[Int]]. Вот (слегка измененный для простоты) вариант Haskell, так как я не очень хорошо говорю Scala.

module Main where 

import Control.Monad.State 
import Data.IntSet (IntSet) 
import qualified Data.IntSet as IntSet 
import Data.Maybe (isJust) 

step :: Int -> State IntSet (Maybe [Int]) 
step i = do 
    set <- get 
    if not (IntSet.member i set) 
    then do 
     modify $ IntSet.insert i 
     return $ Just [i, i*10, i*100] 
    else return Nothing 

run xs = filter isJust $ flip evalState IntSet.empty $ mapM step xs 

main = do 
    let result = run [1,2,1,3] 
    print result 

То, что вы действительно хотите mapM или любой другой эквивалент Scala является. Затем просто запустите действие State и удалите значения Nothing.

+0

Благодарим вас за разъяснение! –

 Смежные вопросы

  • Нет связанных вопросов^_^