Как ты делаешь синглтон в Racket? - PullRequest
0 голосов
/ 12 сентября 2018

Как сделать значение в Racket таким, чтобы никакой другой код не мог создать значение equal? для этого значения?

Причина, по которой я хочу это, состоит в том, чтобы обозначать заполнитель внутри различных других структур данных.Например, предположим, что у нас есть небольшая коллекция атрибутов ключ-значение, таких как:

'((name . breakfast) (successor . lunch) (predecessor . placeholder))

(define (placeholder? x) (eq? x 'placeholder))

Цель состоит в том, чтобы показать, что предшественник breakfast в настоящее время неизвестен, поэтому временно мы помещаемзаполнитель в этом слоте.Мы наполним это реальным предшественником позже.Вышеприведенное не совсем верно, потому что нельзя сказать, что предшественник breakfast действительно является символом 'placeholder.(Аналогично для представления специальных вещей, таких как «не имеет ни одного».) Примерно так можно решить эту проблему:

(define placeholder (make-unique-value)
(define (placeholder? x) (eq? x placeholder))

`((name . breakfast) (successor . lunch) (predecessor . ,placeholder))

Поскольку placeholder является специальным значением, вы не можете случайно сделать другоепросто сделав символ 'placeholder.Было бы хорошо, если бы уникальное значение placeholder ни к чему не было бы equal?;таким образом, он также может служить ключом в хеш-таблицах или где угодно.Дело в том, что вам не нужно беспокоиться о «гочах».

Если создание уникального значения, например #t или #f, не способ сделать это в Racket, я бы согласилсяответ, который показал Rackety способ сделать это.

Ответы [ 3 ]

0 голосов
/ 12 сентября 2018

С помощью gensym вы можете создать систему уникальных значений.

Например:

#lang racket

(define placeholder-unique-prefix "#$#@")

(define (new-placeholder)
  (gensym placeholder-unique-prefix))

(define (placeholder? x)
  (and (symbol? x)
       (string-prefix? (symbol->string x) placeholder-unique-prefix)))

(define placeholder1 (new-placeholder))
(define placeholder2 (new-placeholder))

(define cons1 (cons 'a placeholder1))

(define cons2 (cons 'b placeholder2))

(eq? (cdr cons1) placeholder1)  =>  #t

(eq? (cdr cons2) placeholder1)  =>  #f

(placeholder? (cdr cons1))      =>  #t

(placeholder? (cdr cons2))      =>  #t
0 голосов
/ 12 сентября 2018

Лучший способ сделать это в Racket - создать локальную непрозрачную структуру и создать один экземпляр этого типа структуры.Поскольку структуры являются порождающими (то есть каждая оценка формы struct создает совершенно уникальный тип структуры), это значение гарантированно будет уникальным.

Код для этого обычно выглядит примерно так:

(define placeholder
  (let ()
    (struct placeholder ())
    (placeholder)))

Создает уникальное непрозрачное значение в placeholder:

> placeholder
#<placeholder>
> (equal? placeholder placeholder)
#t
> (equal? placeholder #t)
#f
0 голосов
/ 12 сентября 2018

Я думал о способе сделать это. Это, вероятно, выполнимо, но это беспокоит меня.

(struct unique [])

(define placeholder (unique))
(define (placeholder? x) (eq? x placeholder))

(define not-applicable (unique))
(define (not-applicable? x) (eq? x not-applicable))

(equal? placeholder not-applicable) ; => #f

Что меня беспокоит, так это то, что это работает очень тонко. Он работает, используя тот факт, что определение структуры отсутствует #:transparent. Если вы сделаете unique прозрачным, то каждый unique будет equal? для всех остальных, что означает, что они не уникальны:

(struct unique [] #:transparent)

(define placeholder (unique))
(define not-applicable (unique))

(equal? placeholder not-applicable) ; => #t

Если возможно, я бы хотел, чтобы значение и действительность кода были очевидны при проверке.

...