Реализация ленивой последовательности (строки) Clojure в REPL

Я пытаюсь реализовать ленивую последовательность (которая должна генерировать одну строку) в REPL, но безуспешно. Исходный код работает нормально:

(def word_list ["alpha" "beta" "gamma" "beta" "alpha" "alpha" "beta" "beta" "beta"])
(def word_string (reduce str (interpose " " word_list))); 
word_string ; "alpha beta gamma beta alpha alpha beta beta beta"

Но не желая оставлять достаточно хорошо в покое, я подумал, что еще сработает, и попытался удалить reduce, думая, что str может иметь такой же эффект. Это не ...

(def word_string (str (interpose " " word_list)))
word_string ; "clojure.lang.LazySeq@304a9790"

Я попробовал очевидное, снова используя reduce, но это тоже не сработало. Есть другой вопрос о реализации ленивых последовательностей, которые казались многообещающими, но ничего из того, что я пробовал, не сработало:

(reduce str word_string)   ; "clojure.lang.LazySeq@304a9790"
(apply str word_string)    ; "clojure.lang.LazySeq@304a9790"
(println word_string)      ; "clojure.lang.LazySeq@304a9790"
(apply list word_string)   ; [\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...]
(vec word_string)          ; [\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...]
(apply list word_string)   ; (\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...)
(take 100 word_string)     ; (\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...)

Тот факт, что некоторые из вариантов дали мне символы в "clojure.lang.LazySeq", также меня беспокоит - я каким-то образом потерял фактическое строковое значение, а моя ссылка просто имеет значение "clojure". lang.LazySeq "? Если нет, как мне на самом деле осознать ценность?

Чтобы уточнить: учитывая, что word_string назначен ленивой последовательности, как мне это реализовать? Что-то вроде (realize word_string), если бы такое существовало.

Обновление: исходя из принятого ответа и того, как str работает, оказывается, что я могу получить фактическое значение последовательности, а не только ее имя:

(reduce str "" word_string) ; "alpha beta gamma beta alpha alpha beta beta beta"

Да, это ужасный код. :) Я просто пытался понять, что происходит, почему это ломалось, и было ли реальное значение все еще там или нет.


person John C    schedule 31.10.2015    source источник


Ответы (2)


Вы хотите:

(def word_string (apply str (interpose " " word_list)))

Посмотрите документацию str:

Без аргументов возвращает пустую строку. С одним аргументом x возвращает
x.toString (). (str nil) возвращает пустую строку. С более чем
одним аргументом возвращает объединение значений str аргументов.

Итак, вы вызываете .toString в последовательности, которая генерирует это представление вместо применения str к элементам последовательности в качестве аргументов.

Кстати, более идиоматический способ делать то, что вы хотите:

(clojure.string/join " " word_list)

Кроме того, строка - это не ленивая последовательность. interpose возвращает ленивую последовательность, и вы вызываете .toString по этому поводу.

person Diego Basch    schedule 31.10.2015
comment
Думаю, я не совсем понял свой вопрос - я смог назначить полностью реализованную строку для word_string с помощью reduce, хотя apply может быть лучше. Но учитывая, что word_string был назначен на ленивую последовательность, как мне это реализовать? Какую операцию я бы применил к word_string, например (realize word_string)? - person John C; 31.10.2015
comment
Я думаю, вы сбиты с толку: второе присвоение word_string не ленивой последовательности; это строка, которая является результатом вызова .toString в ленивой последовательности. Строковое представление ленивой последовательности не очень полезно и не то, что вам нужно. См. Этот вопрос: stackoverflow.com/questions/7946219/ - person Diego Basch; 31.10.2015
comment
Да, я определенно запуталась. :) В Clojure есть много странных, ошибочных, неинтуитивных аспектов, ленивых последовательностей и т.д., над пониманием которых я все еще работаю. Однако я думаю, что понимаю, что произошло в этом случае, str не делает то, что я думал изначально. Спасибо. - person John C; 01.11.2015

Вам не нужно делать ничего особенного, чтобы реализовать ленивый seq в clojure, вы просто используете его в любом месте, где ожидается seq.

user=> (def word-list ["alpha" "beta" "gamma" "beta" "alpha" "alpha" "beta" "beta" "beta"])
#'user/word-list
user=> (def should-be-a-seq (interpose " " word_list))
#'user/should-be-a-seq
user=> (class should-be-a-seq)
clojure.lang.LazySeq

Итак, у нас есть seq, если я использую его в любом случае, который перебирает все значения в seq, он в конечном итоге будет полностью реализован. например

user=> (seq should-be-a-seq)
("alpha" " " "beta" " " "gamma" " " "beta" " " "alpha" " " "alpha" " " "beta" " " "beta" " " "beta")

Хотя это все еще seq, на самом деле это все тот же объект, что и раньше.

user=> (str should-be-a-seq)
"clojure.lang.LazySeq@304a9790"

Как упоминал Диего Баш, вызов str для чего-либо аналогичен вызову .toString, который для метода LazySeq, по-видимому, является просто значением по умолчанию .toString, унаследованным от Object.

Поскольку это seq, вы можете использовать его как любой seq, независимо от того, был он полностью реализован ранее или нет. например

user=> (apply str should-be-a-seq)
"alpha beta gamma beta alpha alpha beta beta beta"
user=> (reduce str should-be-a-seq)
"alpha beta gamma beta alpha alpha beta beta beta"
user=> (str/join should-be-a-seq)
"alpha beta gamma beta alpha alpha beta beta beta"
user=> (str/join (map #(.toUpperCase %) should-be-a-seq))
"ALPHA BETA GAMMA BETA ALPHA ALPHA BETA BETA BETA"
person Bill    schedule 31.10.2015
comment
Если вы используете str, как это сделал я, хотя (def should-be-a-seq (str (interpose " " word_list))), он ведет себя иначе. Должен ли я использовать str - это, безусловно, правильный вопрос, но я пытаюсь понять, что было назначено для (def word_string (str (interpose " " word_list))), и как им управлять. - person John C; 31.10.2015
comment
@JohnC str возвращает строку. В данном случае это просто не та строка, которая вам нужна. - person Diego Basch; 31.10.2015