В 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
Я хотел бы перевести это на 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)
Это не удается, поскольку я думаю, что это самый очевидный способ: "значение flatMap не является членом параметра типа M [T1]". Правильно, я не указал, что M[_]
- это какая-то монада. Итак, следующая вещь, которую я пробовал, заключалась в определении некоторого структурного типа:
type Monad[A] = {
def flatMap[B](f: (A) => Monad[B]): Monad[B]
}
... и иметь M[A] <: Monad[A]
. Но это не работает, потому что Scala не имеет рекурсивных структурных типов.
Итак, следующие несколько вещей, которые я пробовал, включали в себя гироскопы, похожие на M[A] <: FilterMonadic[A, _]
. Все это не удалось, вероятно, потому, что я не смог определить правильное значение implicit-fu для CanBuildFrom
.
Наиболее близкий вопрос, который я мог найти здесь, в StackOverflow, был этот, касаясь как рекурсивных структурных типов, так и того, как имитировать классные классы Haskell в Scala. Но для этого подхода требуется определение неявного преобразования из каждого типа, который вам нужен, для определения, определяющего класс стилей, который в этом случае кажется ужасно круговым.
Есть ли хороший способ сделать то, что я пытаюсь сделать?