Как применить функцию несколько раз, чтобы получить бесконечную последовательность?

Например,

(require racket/generator)
(define f add1)
(define init 0)
(in-producer (generator () (let loop ([x init]) (yield x) (loop (f x)))))

Есть ли лучший способ сделать это? Я не очень люблю генераторы, так как у них есть скрытые состояния.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
125
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Потоки

Использование потоки, вероятно, является самым простым:

(require racket/stream)

;; X [X -> X] -> [Streamof X]
(define (repeated-fn-stream init f)
  (stream-cons init (repeated-fn-stream (f init) f)))

(repeated-fn-stream 0 add1)

Последовательности

В качестве альтернативы, используя последовательности и make-do-sequence:

(require racket/sequence)

;; X [X -> X] -> [Sequenceof X]
(define (repeated-fn-sequence init f)
  ;; A "Pos" is an X that's the result of applying f repeatedly to init
  (define (pos->element pos) pos)
  (define (next-pos pos) (f pos))
  (define init-pos init)
  (make-do-sequence
   (λ ()
     (values pos->element
             next-pos
             init-pos
             #false
             #false
             #false))))

(repeated-fn-sequence 0 add1)

Если вы хотели использовать последовательности, и, вы хотели использовать define-sequence-syntax, чтобы циклы for специализировались на нем:

(для "чистого" функционала это совершенно не нужно, но может иметь другие характеристики производительности)

(require (for-syntax syntax/parse))

(define-sequence-syntax in-repeated-fn-sequence
  (λ () #'repeated-fn-sequence) ; when used as a normal expression
  (syntax-parser                ; when used *directly* as a for-loop clause
    [[(x) (_ init-expr f-expr)]
     #'[(x) (:do-in
             ([(init) init-expr] [(f) f-expr])
             #true
             ([x init])
             #true
             ()
             #true
             #true
             [(f x)])]]))

(for/list ([x (in-repeated-fn-sequence 0 add1)]
           [i (in-range 10)])
  x)

При использовании define-sequence-syntax следует убедиться, что для всего существует «единая точка истины».. Из-за этого вы часто видите такую ​​закономерность:

(define-sequence-syntax in-___
  (λ () #'in-___/proc) ; when used as a normal expression
  (syntax-parser
    ....everything that defines the actual functionality....))

;; This is completely determined by the sequence-syntax above,
;; that way there is NO duplicated functionality and NO chance for
;; it to get "out of sync".
(define (in-___/proc parameter ...)
  (for/stream ([elem (in-___ parameter ...)])
    elem))

Это означает, что как только вы решите использовать define-sequence-syntax, вы должны определить repeated-fn-sequenceфункция в терминах этого:

(define (repeated-fn-sequence init f)
  (for/stream ([elem (in-repeated-fn-sequence init f)])
    elem))

Таким образом, если in-repeated-fn-sequence необходимо заменить для исправления ошибки или переключения представлений, версия функции автоматически изменится вместе с ней.

Спасибо. Я не понимал, что stream-cons - это особая форма. Похоже, для этого используется много памяти. Кешируются ли результаты потоками? Обновлено: Я изучаю последовательность действий.

ntysdd 27.08.2018 08:27

Да, они кешируют или "запоминают" результаты

Alex Knauth 27.08.2018 08:27

Лучшая функция для этой работы - развернуться… но, к сожалению, Racket не поддерживает встроенную операцию sequence-unfold или stream-unfold. Однако в библиотеке stream-unfold есть является операция srfi/41, которая соответствует вашим потребностям. Вы можете увидеть это в действии с помощью следующей программы:

#lang racket

(require (only-in srfi/41 stream-unfold))

(define nats (stream-unfold identity (const #t) add1 0))

(for/list ([i (in-range 20)] [n nats]) n)

Это дает следующий результат:

'(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)

Если вы не хотите использовать srfi/41, вы можете написать stream-unfold самостоятельно в терминах API racket/stream без особых трудностей и без сохранения состояния:

(define (stream-unfold mapper pred? gen base)
  (let loop ([base base])
    (if (pred? base)
        (stream-cons (mapper base) (loop (gen base)))
        empty-stream)))

Спасибо. Я не знал, что это называется разворачиванием.

ntysdd 27.08.2018 08:41

Другие вопросы по теме