В Haskell liftM2
можно определить как:
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 f m1 m2 = do
x1 <- m1
x2 <- m2
return $ f x1 x2
I ' Я хотел бы перевести это на Scala. Моя первая попытка была следующей:
def liftM2[T1, T2, R, M[_]](f: (T1, T2) => R)(ma: M[T1], mb: M[T2]) : M[R] = for {
a <- ma
b <- mb
} yield f(a, b)
Это терпит неудачу, как я полагаю, наиболее очевидным из возможных способов: «value flatMap не является членом параметра типа M [T1]». Правильно, я не указал, что M [_]
- это какая-то монада. Итак, следующее, что я попытался, - это определить некоторый структурный тип, например:
type Monad[A] = {
def flatMap[B](f: (A) => Monad[B]): Monad[B]
}
... и иметь M [A] <: monad>. Но это не работает, потому что в Scala нет рекурсивных структурных типов.
Следующие несколько вещей, которые я попробовал, были связаны с вращениями, подобными M [A] <: filtermonadic _>. Все они потерпели неудачу, вероятно, из-за того, что я не смог определить правильное implicit-fu для
CanBuildFrom
.
Самый близкий вопрос, который я смог найти здесь, в StackOverflow, был этот , касающийся как рекурсивных структурных типов, так и того, как имитировать классы типов Haskell в Scala. Но этот подход требует определения неявного преобразования каждого типа, который вас интересует, в черту, определяющую класс типов, что в данном случае кажется ужасно замкнутым ...
Есть ли хороший способ сделать то, что я пытаюсь сделать?