Clojure seq в качестве замены для Scala Option [T] - PullRequest
4 голосов
/ 19 октября 2011

Scala предлагает иерархию классов Option[T], Some[T] extends Option[T] и None extends Option[Nothing], которые я нашел полезными для упаковки вызовов методов Java, которые могут возвращать null, среди прочего:

val result = Option(someJavaMethodThatReturnsNull())

result действует как последовательность из нуля или одного элемента, в зависимости от того, вернул ли Java-метод объект или null. Option имеет такие методы, как map, filter и т. Д., Которые вы можете использовать точно так же, как и в последовательности, и либо возвращать новую последовательность (Some), если оригинал был Some[T], либо None если оригинал был None.

Похоже, что функция Clojure seq ведет себя аналогично: (seq x) будет последовательностью из одного элемента, если x не нуль, или nil, если x ноль. Затем это значение может быть передано (map ...), (filter ...) и т. Д., Как и методы Scala Option.

Я что-то упустил? Имеет ли этот шаблон смысл? Это "Эврика!" момент, который очевиден для опытных программистов Clojure?

Ответы [ 4 ]

2 голосов
/ 11 января 2012

Вы, конечно, можете использовать последовательность Clojure для представления нуля, одного или нескольких возвращаемых значений.

Это разумный и очень идиоматичный подход, если ваша функция действительно должна возвращать коллекцию.

Однако я бы не рекомендовал использовать последовательность для эмуляции типа параметра,Это может запутать пользователей вашего API.В Clojure обычный идиоматический способ - просто вернуть nil, если значение недоступно, и вернуть значение напрямую, если оно есть.

Сравните:

  (if-let [a (function-that-returns-nil-or-result)]
    (do-something-with a))

С тем, что выпонадобится, если вы использовали последовательность для эмуляции типа параметра:

  (if-let [a (function-that-returns-a-possibly-empty-sequence)]
    (do-something-with (first a)))  

Я определенно предпочитаю первый вариант .... зачем нам или нужно, чтобы пользователь API распаковывал результат из последовательности с помощью first?

В целом, nil работает довольно хорошо в Clojure (намного лучше, чем в других языках), потому что:

  • Все функции библиотеки интерпретируют nil как пустую последовательность, поэтомугораздо реже встречаются с NullPointerExceptions.
  • nil также считается "ложным", поэтому его удобно использовать в логических операциях.
2 голосов
/ 19 октября 2011

Вы всегда можете использовать может быть, монаду , которая близка к опции Scala (и haskell Maybe), конечно, без статической безопасности типов.

Также существует семейство?функции работы с потоками (.?. - лучший выбор для взаимодействия с Java)

1 голос
/ 19 октября 2011

Нет. seq либо возвратит абстрактное последовательное представление коллекции, если коллекция не пуста. nil в противном случае. Так что это совершенно не связано с тем, что вы хотите. Однако вы можете использовать nil в тестах if. например.

(when-let [thing (.someMethodThatReturnsSomethingOrNil other-thing)]
  (run-only-when thing is-not-nil-or-false))

Это то, что вы намереваетесь?

Редактировать: Остерегайтесь ложных.

0 голосов
/ 19 октября 2011

(seq x) вернет nil, если x равно nil или пустая коллекция. Однако map, filter и т. Д. Примут nil в качестве аргумента сбора (т. Е. Они не сломаются) и вернут пустую последовательность. Это может дать результат, который вы ожидаете от Option заявления Scala.

Следующее будет возвращать пустую последовательность:

(map (fn [x] x) (seq nil))
(map (fn [x] x) (seq `()))
(filter even? (seq nil))
(filter even? (seq `()))
...