Как преобразовать эту карту/flatMap в для понимания в Clojure?

Учитывая этот код Scala :

def compute2(maybeFoo: Option[Foo]): Option[Int] =
  maybeFoo.flatMap { foo =>
    foo.bar.flatMap { bar =>
      bar.baz.map { baz =>
        baz.compute
      }
    }
  }  

Который затем переводится на это для понимания:

def compute2(maybeFoo: Option[Foo]): Option[Int] =
  for {
    foo <- maybeFoo
    bar <- foo.bar
    baz <- bar.baz
  } yield baz.compute

Мой вопрос: Как преобразовать эту карту/flatMap в для понимания в Clojure?

Предположения:

  • Если возможно, я бы хотел использовать идиоматический Clojure (т.е. mapcat) для представления этого, а не библиотеки algo.monads/fluokitten. Но если это лучший способ сделать это (я открыт для обучения), тогда используйте его.

person hawkeye    schedule 03.09.2014    source источник


Ответы (1)


Вы, вероятно, не будете использовать Option в Clojure, но если объекты находятся внутри коллекций, должно работать что-то вроде этого:

(let [maybe-foo [{:bar [{:baz [(fn [] 42)]}]}]]
  (for [foo maybe-foo
        bar (:bar foo)
        baz (:baz bar)]
    (baz)))
 ;=> '(42)

(let [maybe-foo [{:bar nil}]]
  (for [foo maybe-foo
        bar (:bar foo)
        baz (:baz bar)]
    (baz)))
;=> '()

(let [maybe-foo nil]
  (for [foo maybe-foo
        bar (:bar foo)
        baz (:baz bar)]
    (baz)))
  ;=> '()
person ponzao    schedule 04.09.2014
comment
Итак, если мы хотим использовать Option, то мы возвращаемся к algo.monads onclojure.com/2009/03/05/ — это правильно? - person hawkeye; 04.09.2014
comment
@hawkeye, чтобы использовать for, вам нужно, чтобы объекты были обернуты в последовательности, если это не нормально, вам, вероятно, нужно использовать algo.monads (или свернуть свой собственный). - person ponzao; 04.09.2014
comment
Хорошо, вы говорите, что for-comprehension - это, по сути, цикл for с блоком let вверху? - person hawkeye; 04.09.2014
comment
@hawkeye, на самом деле нет. Как вы можете видеть из моих примеров, на каждом этапе он сглаживает коллекцию, а также останавливает оценку, если какая-либо из коллекций пуста. С for+let вам нужно будет сопоставить коллекции вручную, а также сгладить их. - person ponzao; 04.09.2014
comment
@hawkeye (1) Я не говорю на Scala, но похоже, что Option[Foo] указывает, что maybeFoo может быть объектом, а может быть ничем. В Clojure мы используем nil ни за что, и он соответствует ожидаемой последовательности (for [x nil] x) ;=> ()). (2) для понимания подобна записи монады списка в Haskell. - person A. Webb; 04.09.2014