Задать разность операций между телом объекта и определением блока в Rebol - PullRequest
0 голосов
/ 18 декабря 2009

Я хочу иметь возможность динамически изменять объект, добавляя / удаляя свойства или методы на лету. Для добавления не проблема, для удаления я думал об использовании математического оператора Set Difference, но он ведет себя странно, насколько я вижу при удалении метода из объекта.

Например, если у меня есть

O: make object! [
    a: 1        
    f: func [][]
    b: 1
]

Я могу вычесть [a: 1 b: 1] без проблем

>> difference third O [b: 1 a: 1]
== [f: func [][]]

Но я не могу вычесть f: func [] []:

>> difference third O [f: func[][]]
== [a: 1 b: func [][] func []]
>>

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

Почему и что я должен делать вместо этого?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 03 января 2010

Проблема № 1: Разница сбрасывает дубликаты с обоих входов

Во-первых, difference не следует рассматривать как оператор "вычитания". Это дает вам один из каждого элемента, который уникален в каждом блоке:

>> difference [1 1 2 2] [2 2 2 3 3 3]
== [1 3]

>> difference [2 2 2 3 3 3] [1 1 2 2]
== [3 1]

Таким образом, вы получите эквивалентный набор, если сравнить с [a: 1 b: 1] и [1 a: b:]. Вот почему второй 1 отсутствует в вашем конечном выводе. Даже различие с пустым набором удалит все повторяющиеся элементы:

>> difference [a: 1 b: 1] []
== [a: 1 b:]

Если вы на самом деле ищите и замените известный последовательный шаблон , то скорее всего вам нужно replace с заменой в качестве пустого набора:

>> replace [a: 1 b: 1] [b: 1] []
== [a: 1]

Проблема № 2: равенство функций основано на идентичности

Две отдельные функции с одним и тем же определением будут оценивать два разных функциональных объекта. Например, обе эти функции не принимают параметров и не имеют тела, но когда вы используете get-word! для их извлечения и сравнения, они не равны:

>> foo: func [] []
>> bar: func [] []

>> :foo == :bar
== false

Итак, еще один фактор в вашем странном результате заключается в том, что f: вычитается из набора, и две (разные) пустые функции уникальны и, таким образом, оба являются членами разностного набора.

R2 немного страннее, чем R3, и я не могу заставить :o/f работать. Но вот способ получить «искусственно выглядящую версию» разницы, которую вы пытаетесь достичь:

>> foo: func [] []

>> o: make object! [a: 1 f: :foo b: 2]

>> difference third o compose [f: (:foo)]  
== [a: 1 b: 2]

Здесь вы используете тот же идентификатор функции, который вы поместили в объект в блоке, который вычитаете.

В R3, difference не поддерживает значения функций таким образом. Это может относиться к базовой реализации, основанной на map!, которая не может иметь «функциональные значения» в качестве ключей. Также в Rebol 3 использование различий на объекте недопустимо. Так что даже ваш первый случай не сработает. (

Проблема № 3: Это не то, как добавлять и удалять свойства

В Rebol 3 вы можете добавлять свойства к объекту динамически без проблем.

>> obj: object [a: 1]
== make object! [
    a: 1
]

>> append obj [b: 2]
== make object! [
   a: 1
   b: 2
]

Но, насколько я знаю, вы не можете удалить их, как только они были добавлены. Конечно, вы можете установить их на none, но API отражения все равно будут сообщать о них как о находящихся там.

Если вы хотите, чтобы попытка их чтения вызвала ошибку, вы можете установить для нее объект ошибки и затем защитить их от чтения. Вариант этого также работает в R2:

>> attempt [obj/b: to-error "invalid member"]
== none

>> probe obj
== make object! [
    a: 1
    b: make error! [
        code: 800
        type: 'User
        id: 'message
        arg1: "invalid member"
        arg2: none
        arg3: none
        near: none
        where: none
    ]
]

>> obj/b
** User error: "invalid member"

R3 делает еще один шаг вперед и позволяет защитить участника от записи и даже скрыть от участника новые привязки.

>> protect 'obj/b
== obj/b

>> obj/b: 100
** Script error: protected variable - cannot modify: b

>> protect/hide 'obj/b
== obj/b

>> obj
== make object! [
    a: 1
]

Если вам нужно динамически добавлять и удалять элементы в R2, вы можете также рассмотреть элемент данных в вашем объекте, который является блоком. Блоки и объекты взаимозаменяемы для многих операций, например:

>> data: [a: 1 b: 2]
== [a: 1 b: 2]

>> data/a
== 1

>> data/b
== 2

И вы можете удалить вещи из них ...

>> remove/part (find data (to-set-word 'a)) 2
== [b: 2]

Все зависит от вашего приложения. Главное, что у object! есть над block!, - это способность служить контекстом для связывания слов ...

0 голосов
/ 24 декабря 2009

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

...