<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.1.1.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.23.0/ramda.min.js"></script>
<script src="https://code.jquery.com/qunit/qunit-2.1.1.js"></script>
</body>
</html>
/* jshint esnext: true */
// miniKanren
function mKanren() {
function LVar(id) {
return Symbol.for('LVar' + id)
}
function isLVar(a) {
return typeof a === 'symbol'
&& /Symbol\(LVar[0-9]+\)/.test(a.toString())
}
function addSubstitution(subMap, lVar, value) {
if (subMap instanceof Map) {
subMap.set(lVar, value)
return subMap
}
else {
return null
}
}
function walk(u, subMap) {
if (isLVar(u)) {
var value = u
while (subMap.get(value) !== null && subMap.get(value) !== undefined) {
value = subMap.get(value)
}
return value
}
else {
return u
}
}
function unify(_u, _v, subMap) {
let u = walk(_u, subMap)
, v = walk(_v, subMap)
if (u === v)
return subMap
else if (isLVar(u))
return addSubstitution(subMap, u, v)
else if (isLVar(v))
return addSubstitution(subMap, v, u)
else
return null
}
function printMap(subMap) {
if (subMap instanceof Map) {
var keys = Array.from(subMap.keys())
return keys.reduce(function(acc, key) {
acc[key.toString()] = subMap.get(key)
return acc
}, {})
}
else
return subMap
}
function equalsMap(s1, s2) {
return R.equals(printMap(s1), printMap(s2))
}
function emptyState() {
return {subMap: {}, nextId: 0}
}
function goal(u, v) {
return function(state) {
var subMap = unify(u, v, state.subMap)
if (subMap !== null && subMap !== undefined)
return R.assoc('subMap', subMap, state)
else
return emptyState()
}
}
function callFresh(goalConstructor) {
return function(state) {
var goal = goalConstructor(LVar(state.nextId))
return goal(R.assoc('nextId', state.nextId + 1, state))
}
}
function disjunction(goal1, goal2) {
return function(state) {
var goal1State = goal1(state)
, goal2State = goal2(state)
return R.flatten([goal1State, goal2State])
}
}
function conjunction(goal1, goal2) {
return function(state) {
goal1 = goal1 instanceof Array ? goal1 : [goal1]
return goal1.map(goal => goal2(state))
}
}
this.LVar = LVar
this.isLVar = isLVar
this.addSubstitution = addSubstitution
this.walk = walk
this.unify = unify
this.print = printMap
this.equals = equalsMap
}
var K = new mKanren()
QUnit.test('K.walk', assert => {
var subMap = new Map([ [K.LVar(0), K.LVar(1)]
, [K.LVar(1), 'banana']
])
assert.ok(K.walk(K.LVar(0), subMap) === 'banana')
assert.ok(K.walk(K.LVar(1), subMap) === 'banana')
assert.ok(K.walk('mango', subMap) === 'mango')
})
QUnit.test('K.unify', assert => {
assert.ok(
K.equals(
K.unify('banana', K.LVar(0), new Map()),
new Map([[K.LVar(0), 'banana']])
)
)
assert.ok(
K.equals(
K.unify(K.LVar(0), 'banana', new Map()),
new Map([[K.LVar(0), 'banana']])
)
)
assert.ok(
K.equals(
K.unify(K.LVar(0), 'banana', new Map([[K.LVar(0), 'banana']])),
new Map([[K.LVar(0), 'banana']])
)
)
assert.ok(
K.equals(
K.unify(K.LVar(0), 'mango', new Map([[K.LVar(0), 'banana']])),
null
)
)
assert.ok(
K.equals(
K.unify(K.LVar(0), 'banana', new Map([[K.LVar(9), 'squirrels']])),
new Map([[K.LVar(0), 'banana'], [K.LVar(9), 'squirrels']])
)
)
// Transitivity
var newSubMap = K.unify(K.LVar(1), K.LVar(2), new Map([[K.LVar(0), K.LVar(1)]]))
assert.ok(
K.equals(
K.walk(K.LVar(0), newSubMap),
K.walk(K.LVar(1), newSubMap)
)
)
})
Output
This bin was created anonymously and its free preview time has expired (learn why). — Get a free unrestricted account
Dismiss xKeyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |