2013-08-15 2 views
7

Я просто немного поиграл с ST в scalaz и подошел к точке, где хотел использовать содержимое проходящего типа, чтобы изменить мой STRef. В Haskell я мог бы сделать это следующим образом (взяты из вики Haskell):Scalaz, эквивалентный forM_

sumST :: Num a => [a] -> a 
sumST xs = runST $ do 

    n <- newSTRef 0 

    forM_ xs $ \x -> do 
     modifySTRef n (+x) 

    readSTRef n 

К сожалению, я не смог найти эквивалент forM_ в scalaz. Итак, вопрос в том, как я могу это сделать со сказазом?

ответ

6

Как вы, вероятно, знаете, forM_ - это перевернутая версия mapM_.

Вы можете использовать traverse и traverse_ (которые являются реализованными в Scalaz), как обобщенные версии mapM и mapM_.

В качестве доказательства см. То, что Data.Traversable экспортирует собственную реализацию mapM, с точки зрения traverse.

версия scalaz из sumST может выглядеть следующим образом:

def sumST[S, A](as: List[A])(implicit A: Numeric[A]): ST[S, A] = 
    for { n <- newVar(A.zero) 
     _ <- as.traverseU(a => n.mod(A.plus(_, a))) 
     m <- n.read } yield m 

def sum[A : Numeric](as: List[A]): A = 
    runST(new Forall[({type λ[S] = ST[S, A]})#λ] { 
    def apply[S] = sumST[S, A](as) 
    }) 

Для читателей интересно, почему это так гораздо более многословно, чем версия Haskell: Мы должны использовать Forall признак для представления ранга-2 полиморфного типа в Скале. См. http://apocalisp.wordpress.com/2011/03/20/towards-an-effect-system-in-scala-part-1/ для более полного объяснения.

+0

Отлично, большое спасибо! – drexin