Уникальный идентификатор для объектов Racket? - PullRequest
1 голос
/ 31 мая 2019

Есть ли способ получить уникальный идентификатор для объекта в Racket?Например, когда мы используем оператор eq? Ракета, чтобы проверить, ссылаются ли две переменные на один и тот же объект , какой идентификатор он использует для достижения этого сравнения?

Я ищу что-токак id функция python или object_id метод Руби , другими словами, некоторая функция id такая, что (= (id obj) (id obj2)) означает, что (eq? obj obj2) истинно.

Некоторые соответствующие документы:

Идентификация объекта и сравнения

Переменные и местоположения

Ответы [ 4 ]

5 голосов
/ 31 мая 2019

Является ли eq-hash-code тем, что вы хотите?

> (define l1 '(1))
> (define l2 '(1))
> (eq? l1 l2)
#f
> (eq-hash-code l1)
9408
> (eq-hash-code l2)
9412
3 голосов
/ 31 мая 2019

Есть способ получить указатель C на объект через ffi/unsafe, с очевидным предостережением, что это НЕ БЕЗОПАСНО.

;; from https://rosettacode.org/wiki/Address_of_a_variable#Racket

(require ffi/unsafe)

(define (madness v) ; i'm so sorry
   (cast v _racket _gcpointer))

Чтобы использовать это:

(define a (list 1 2))
(define b (list 1 2))

(printf "a and b have different address: ~a ~a\n"
        (equal? (madness a) (madness b))
        (eq? a b))

(printf "a and a have the same address: ~a ~a\n"
        (equal? (madness a) (madness a))
        (eq? a a))

(printf "1 and 1 have the same address: ~a ~a\n"
        (equal? (madness 1) (madness 1))
        (eq? 1 1))

Хотя указатель не является числом или идентификатором. Это непрозрачный объект ... Так что в некотором смысле это бесполезно. Вместо этого вы могли бы использовать реальные объекты с eq?.

Я также не знаю никаких гарантий этого метода. В частности, я не знаю, будет ли указатель обновлен до своего последнего значения при копировании объектов GC.

3 голосов
/ 31 мая 2019

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

#lang racket

(define ht (make-weak-hasheq))
(define next 0)

(define (get-id x)
  (define id (hash-ref ht x #f))
  (or id
      (begin0
        next
        (hash-set! ht x next)
        (set! next (+ next 1)))))

(get-id 'a)
(get-id 'b)
(get-id 'a)

Обратите внимание, что совет Сильвестра является обоснованным. Стандарт заключается в прямом сохранении значения.

2 голосов
/ 31 мая 2019

Скорее всего, вы не найдете личность, но сам объект только eq? с самим собой и ничем иным.eq? в основном сравнивает адрес расположения значений.Поэтому, если вам нужен идентификатор, вы можете просто сохранить весь объект в этом месте, и он будет уникальным.

Местоположение является обязательным.Думайте об этом как о адресе, который вы не можете получить, и адресе, который имеет адрес для объекта.Например.Привязка ((lambda (a) a) 10) будет хранить местоположение адреса объекта 10 в первом стековом адресе, а код в теле просто возвращает тот же адрес.Местоположение может измениться на set!, но вы никогда не получите его в памяти.

Обычно системы lisp хранят значения в указателях.Это означает, что некоторые типы и значения на самом деле не имеют объекта по адресу, но адрес содержит закодированные в нем значение и тип, которые знает система.Обычно маленькие целые числа, символы, символы и логические значения могут быть равны указателю, даже если они созданы в разное время.например.'(1 2 3) будет использовать только 3 пары, а не пробел для значений 1-3 и ().

...