{"action":"closed","number":85,"pull_request":{"url":"https://api.github.com/repos/rbrush/clara-rules/pulls/85","id":28882639,"html_url":"https://github.com/rbrush/clara-rules/pull/85","diff_url":"https://github.com/rbrush/clara-rules/pull/85.diff","patch_url":"https://github.com/rbrush/clara-rules/pull/85.patch","issue_url":"https://api.github.com/repos/rbrush/clara-rules/issues/85","number":85,"state":"closed","locked":false,"title":"Proper truth maintenance when retracting equal facts","user":{"login":"mrrodriguez","id":3483575,"avatar_url":"https://avatars.githubusercontent.com/u/3483575?v=3","gravatar_id":"","url":"https://api.github.com/users/mrrodriguez","html_url":"https://github.com/mrrodriguez","followers_url":"https://api.github.com/users/mrrodriguez/followers","following_url":"https://api.github.com/users/mrrodriguez/following{/other_user}","gists_url":"https://api.github.com/users/mrrodriguez/gists{/gist_id}","starred_url":"https://api.github.com/users/mrrodriguez/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrrodriguez/subscriptions","organizations_url":"https://api.github.com/users/mrrodriguez/orgs","repos_url":"https://api.github.com/users/mrrodriguez/repos","events_url":"https://api.github.com/users/mrrodriguez/events{/privacy}","received_events_url":"https://api.github.com/users/mrrodriguez/received_events","type":"User","site_admin":false},"body":"This is a follow up to the issue discussed at https://github.com/rbrush/clara-rules/issues/84.  Facts in working memory with equal values had a potential\r\nto not be properly retracted due to sets being used to group together facts to retract.\r\n\r\nThe biggest changes here are to the `clara.rules.memory/remove-first-of-each` function.  The former set of items to remove is now an arbitrary seq instead to account for duplicates.\r\nThe changes are a bit verbose in order to preserve the efficiency of this function via low-level looping and the use of transients.\r\n\r\n\r\n----\r\nI noted a few points to consider:\r\n\r\n--\r\n(1)\r\n\r\nThe most common usage of this function is in clara.rules.memory itself and it has the form:\r\n\r\n```clj\r\nfiltered-elements (remove-first-of-each elements previous-elements)\r\n\r\n```\r\n\r\nFollowed shortly by logic to return the removed elements.\r\n\r\nThis is doing redundant work and probably (previously at least) would be putting the previous-elements into a set repeatedly.  This could potentially have non-trivial overhead.  Also, to be safe on the consistency of duplicates items being removed and accurately reported, I thought it made sense to shift the responsibility of reporting what was removed to the `remove-first-of-each` function itself.\r\n\r\nI have changed this function to return a tuple of `[items-removed coll-with-items-removed]` and I updated the docs.\r\nI realize this makes the return value a little less \"clean\", but I think it is justified here.\r\n\r\n--\r\n(2) \r\n\r\nThe return value from functions `remove-elements!` and `remove-tokens!` are a LazySeq with this implementation, where they used to be a set.  I looked around where they are being used at and I do not think that this detail matters.\r\n\r\n--\r\n(3)\r\n\r\nI noticed that `remove-first-of-each` does not necessarily (not likely actually) preserve the order of the given coll since it rebuilds a seq from two other seq adding to the efficient end, which is the front.  I do not think this is an important detail, but if there I am curious if there is any advantage in preserving the order or not.  I'm thinking that it is not important at all, so I just left it alone for now.\r\n\r\nFor future reference if it comes up something like this could work:\r\n\r\n```clj\r\n(into (vec before-it) after-it)\r\n```\r\n","created_at":"2015-02-08T16:38:38Z","updated_at":"2015-02-09T00:38:45Z","closed_at":"2015-02-09T00:38:45Z","merged_at":"2015-02-09T00:38:45Z","merge_commit_sha":"91bb5fe12385885b8572a6c293bccf43a43116a1","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/rbrush/clara-rules/pulls/85/commits","review_comments_url":"https://api.github.com/repos/rbrush/clara-rules/pulls/85/comments","review_comment_url":"https://api.github.com/repos/rbrush/clara-rules/pulls/comments/{number}","comments_url":"https://api.github.com/repos/rbrush/clara-rules/issues/85/comments","statuses_url":"https://api.github.com/repos/rbrush/clara-rules/statuses/21e9608b5d04a8aac5b4005b05dd668992c8e00d","head":{"label":"mrrodriguez:retract-equal-facts","ref":"retract-equal-facts","sha":"21e9608b5d04a8aac5b4005b05dd668992c8e00d","user":{"login":"mrrodriguez","id":3483575,"avatar_url":"https://avatars.githubusercontent.com/u/3483575?v=3","gravatar_id":"","url":"https://api.github.com/users/mrrodriguez","html_url":"https://github.com/mrrodriguez","followers_url":"https://api.github.com/users/mrrodriguez/followers","following_url":"https://api.github.com/users/mrrodriguez/following{/other_user}","gists_url":"https://api.github.com/users/mrrodriguez/gists{/gist_id}","starred_url":"https://api.github.com/users/mrrodriguez/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrrodriguez/subscriptions","organizations_url":"https://api.github.com/users/mrrodriguez/orgs","repos_url":"https://api.github.com/users/mrrodriguez/repos","events_url":"https://api.github.com/users/mrrodriguez/events{/privacy}","received_events_url":"https://api.github.com/users/mrrodriguez/received_events","type":"User","site_admin":false},"repo":{"id":15387814,"name":"clara-rules","full_name":"mrrodriguez/clara-rules","owner":{"login":"mrrodriguez","id":3483575,"avatar_url":"https://avatars.githubusercontent.com/u/3483575?v=3","gravatar_id":"","url":"https://api.github.com/users/mrrodriguez","html_url":"https://github.com/mrrodriguez","followers_url":"https://api.github.com/users/mrrodriguez/followers","following_url":"https://api.github.com/users/mrrodriguez/following{/other_user}","gists_url":"https://api.github.com/users/mrrodriguez/gists{/gist_id}","starred_url":"https://api.github.com/users/mrrodriguez/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mrrodriguez/subscriptions","organizations_url":"https://api.github.com/users/mrrodriguez/orgs","repos_url":"https://api.github.com/users/mrrodriguez/repos","events_url":"https://api.github.com/users/mrrodriguez/events{/privacy}","received_events_url":"https://api.github.com/users/mrrodriguez/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mrrodriguez/clara-rules","description":"Forward-chaining rules in Clojure","fork":true,"url":"https://api.github.com/repos/mrrodriguez/clara-rules","forks_url":"https://api.github.com/repos/mrrodriguez/clara-rules/forks","keys_url":"https://api.github.com/repos/mrrodriguez/clara-rules/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mrrodriguez/clara-rules/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mrrodriguez/clara-rules/teams","hooks_url":"https://api.github.com/repos/mrrodriguez/clara-rules/hooks","issue_events_url":"https://api.github.com/repos/mrrodriguez/clara-rules/issues/events{/number}","events_url":"https://api.github.com/repos/mrrodriguez/clara-rules/events","assignees_url":"https://api.github.com/repos/mrrodriguez/clara-rules/assignees{/user}","branches_url":"https://api.github.com/repos/mrrodriguez/clara-rules/branches{/branch}","tags_url":"https://api.github.com/repos/mrrodriguez/clara-rules/tags","blobs_url":"https://api.github.com/repos/mrrodriguez/clara-rules/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mrrodriguez/clara-rules/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mrrodriguez/clara-rules/git/refs{/sha}","trees_url":"https://api.github.com/repos/mrrodriguez/clara-rules/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mrrodriguez/clara-rules/statuses/{sha}","languages_url":"https://api.github.com/repos/mrrodriguez/clara-rules/languages","stargazers_url":"https://api.github.com/repos/mrrodriguez/clara-rules/stargazers","contributors_url":"https://api.github.com/repos/mrrodriguez/clara-rules/contributors","subscribers_url":"https://api.github.com/repos/mrrodriguez/clara-rules/subscribers","subscription_url":"https://api.github.com/repos/mrrodriguez/clara-rules/subscription","commits_url":"https://api.github.com/repos/mrrodriguez/clara-rules/commits{/sha}","git_commits_url":"https://api.github.com/repos/mrrodriguez/clara-rules/git/commits{/sha}","comments_url":"https://api.github.com/repos/mrrodriguez/clara-rules/comments{/number}","issue_comment_url":"https://api.github.com/repos/mrrodriguez/clara-rules/issues/comments/{number}","contents_url":"https://api.github.com/repos/mrrodriguez/clara-rules/contents/{+path}","compare_url":"https://api.github.com/repos/mrrodriguez/clara-rules/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mrrodriguez/clara-rules/merges","archive_url":"https://api.github.com/repos/mrrodriguez/clara-rules/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mrrodriguez/clara-rules/downloads","issues_url":"https://api.github.com/repos/mrrodriguez/clara-rules/issues{/number}","pulls_url":"https://api.github.com/repos/mrrodriguez/clara-rules/pulls{/number}","milestones_url":"https://api.github.com/repos/mrrodriguez/clara-rules/milestones{/number}","notifications_url":"https://api.github.com/repos/mrrodriguez/clara-rules/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mrrodriguez/clara-rules/labels{/name}","releases_url":"https://api.github.com/repos/mrrodriguez/clara-rules/releases{/id}","created_at":"2013-12-23T04:45:05Z","updated_at":"2015-02-08T01:09:19Z","pushed_at":"2015-02-08T16:35:16Z","git_url":"git://github.com/mrrodriguez/clara-rules.git","ssh_url":"git@github.com:mrrodriguez/clara-rules.git","clone_url":"https://github.com/mrrodriguez/clara-rules.git","svn_url":"https://github.com/mrrodriguez/clara-rules","homepage":"","size":1054,"stargazers_count":0,"watchers_count":0,"language":"Clojure","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"rbrush:master","ref":"master","sha":"2ecdbad04ca84007485cf0f0eb83967f07905dde","user":{"login":"rbrush","id":574824,"avatar_url":"https://avatars.githubusercontent.com/u/574824?v=3","gravatar_id":"","url":"https://api.github.com/users/rbrush","html_url":"https://github.com/rbrush","followers_url":"https://api.github.com/users/rbrush/followers","following_url":"https://api.github.com/users/rbrush/following{/other_user}","gists_url":"https://api.github.com/users/rbrush/gists{/gist_id}","starred_url":"https://api.github.com/users/rbrush/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbrush/subscriptions","organizations_url":"https://api.github.com/users/rbrush/orgs","repos_url":"https://api.github.com/users/rbrush/repos","events_url":"https://api.github.com/users/rbrush/events{/privacy}","received_events_url":"https://api.github.com/users/rbrush/received_events","type":"User","site_admin":false},"repo":{"id":11697963,"name":"clara-rules","full_name":"rbrush/clara-rules","owner":{"login":"rbrush","id":574824,"avatar_url":"https://avatars.githubusercontent.com/u/574824?v=3","gravatar_id":"","url":"https://api.github.com/users/rbrush","html_url":"https://github.com/rbrush","followers_url":"https://api.github.com/users/rbrush/followers","following_url":"https://api.github.com/users/rbrush/following{/other_user}","gists_url":"https://api.github.com/users/rbrush/gists{/gist_id}","starred_url":"https://api.github.com/users/rbrush/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbrush/subscriptions","organizations_url":"https://api.github.com/users/rbrush/orgs","repos_url":"https://api.github.com/users/rbrush/repos","events_url":"https://api.github.com/users/rbrush/events{/privacy}","received_events_url":"https://api.github.com/users/rbrush/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rbrush/clara-rules","description":"Forward-chaining rules in Clojure","fork":false,"url":"https://api.github.com/repos/rbrush/clara-rules","forks_url":"https://api.github.com/repos/rbrush/clara-rules/forks","keys_url":"https://api.github.com/repos/rbrush/clara-rules/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rbrush/clara-rules/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rbrush/clara-rules/teams","hooks_url":"https://api.github.com/repos/rbrush/clara-rules/hooks","issue_events_url":"https://api.github.com/repos/rbrush/clara-rules/issues/events{/number}","events_url":"https://api.github.com/repos/rbrush/clara-rules/events","assignees_url":"https://api.github.com/repos/rbrush/clara-rules/assignees{/user}","branches_url":"https://api.github.com/repos/rbrush/clara-rules/branches{/branch}","tags_url":"https://api.github.com/repos/rbrush/clara-rules/tags","blobs_url":"https://api.github.com/repos/rbrush/clara-rules/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rbrush/clara-rules/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rbrush/clara-rules/git/refs{/sha}","trees_url":"https://api.github.com/repos/rbrush/clara-rules/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rbrush/clara-rules/statuses/{sha}","languages_url":"https://api.github.com/repos/rbrush/clara-rules/languages","stargazers_url":"https://api.github.com/repos/rbrush/clara-rules/stargazers","contributors_url":"https://api.github.com/repos/rbrush/clara-rules/contributors","subscribers_url":"https://api.github.com/repos/rbrush/clara-rules/subscribers","subscription_url":"https://api.github.com/repos/rbrush/clara-rules/subscription","commits_url":"https://api.github.com/repos/rbrush/clara-rules/commits{/sha}","git_commits_url":"https://api.github.com/repos/rbrush/clara-rules/git/commits{/sha}","comments_url":"https://api.github.com/repos/rbrush/clara-rules/comments{/number}","issue_comment_url":"https://api.github.com/repos/rbrush/clara-rules/issues/comments/{number}","contents_url":"https://api.github.com/repos/rbrush/clara-rules/contents/{+path}","compare_url":"https://api.github.com/repos/rbrush/clara-rules/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rbrush/clara-rules/merges","archive_url":"https://api.github.com/repos/rbrush/clara-rules/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rbrush/clara-rules/downloads","issues_url":"https://api.github.com/repos/rbrush/clara-rules/issues{/number}","pulls_url":"https://api.github.com/repos/rbrush/clara-rules/pulls{/number}","milestones_url":"https://api.github.com/repos/rbrush/clara-rules/milestones{/number}","notifications_url":"https://api.github.com/repos/rbrush/clara-rules/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rbrush/clara-rules/labels{/name}","releases_url":"https://api.github.com/repos/rbrush/clara-rules/releases{/id}","created_at":"2013-07-27T01:17:19Z","updated_at":"2015-02-08T19:57:33Z","pushed_at":"2015-02-09T00:38:44Z","git_url":"git://github.com/rbrush/clara-rules.git","ssh_url":"git@github.com:rbrush/clara-rules.git","clone_url":"https://github.com/rbrush/clara-rules.git","svn_url":"https://github.com/rbrush/clara-rules","homepage":"","size":1975,"stargazers_count":294,"watchers_count":294,"language":"Clojure","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":24,"mirror_url":null,"open_issues_count":16,"forks":24,"open_issues":16,"watchers":294,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rbrush/clara-rules/pulls/85"},"html":{"href":"https://github.com/rbrush/clara-rules/pull/85"},"issue":{"href":"https://api.github.com/repos/rbrush/clara-rules/issues/85"},"comments":{"href":"https://api.github.com/repos/rbrush/clara-rules/issues/85/comments"},"review_comments":{"href":"https://api.github.com/repos/rbrush/clara-rules/pulls/85/comments"},"review_comment":{"href":"https://api.github.com/repos/rbrush/clara-rules/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/rbrush/clara-rules/pulls/85/commits"},"statuses":{"href":"https://api.github.com/repos/rbrush/clara-rules/statuses/21e9608b5d04a8aac5b4005b05dd668992c8e00d"}},"merged":true,"mergeable":null,"mergeable_state":"unknown","merged_by":{"login":"rbrush","id":574824,"avatar_url":"https://avatars.githubusercontent.com/u/574824?v=3","gravatar_id":"","url":"https://api.github.com/users/rbrush","html_url":"https://github.com/rbrush","followers_url":"https://api.github.com/users/rbrush/followers","following_url":"https://api.github.com/users/rbrush/following{/other_user}","gists_url":"https://api.github.com/users/rbrush/gists{/gist_id}","starred_url":"https://api.github.com/users/rbrush/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbrush/subscriptions","organizations_url":"https://api.github.com/users/rbrush/orgs","repos_url":"https://api.github.com/users/rbrush/repos","events_url":"https://api.github.com/users/rbrush/events{/privacy}","received_events_url":"https://api.github.com/users/rbrush/received_events","type":"User","site_admin":false},"comments":0,"review_comments":0,"commits":1,"additions":155,"deletions":65,"changed_files":4}}