Можно ли реализовать liftM2 в Scala?

В 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. Но этот подход требует определения неявного преобразования каждого типа, который вас интересует, в черту, определяющую класс типов, что в данном случае кажется ужасно замкнутым ...

Есть ли хороший способ сделать то, что я пытаюсь сделать?

28
задан Community 23 May 2017 в 11:53
поделиться