Last active
October 25, 2019 13:41
-
-
Save bamorim/b58612793921bbab582da0810cc3fb87 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const lang = require("./fm-lang"); | |
const to_net = require("./fm-to-net"); | |
const to_js = require("./fm-to-js"); | |
const json = require("./fm-json"); | |
// Return a term or a reference to it based on a name | |
function name_to_term(name, defs) { | |
if (defs[name] && defs[name][0] === "Ref" && !defs[defs[name][1].name]) { | |
name = defs[name][1].name; | |
} | |
return defs[name] || lang.Ref(name); | |
} | |
// Returns the type of a term. Can pass a term or a name to it. | |
function type(term_or_name, defs, opts = {}) { | |
const term = name_to_term_if_not_term(term_or_name, defs); | |
lang.boxcheck(term, defs); | |
const type = lang.typecheck(term, null, defs) | |
return lang.norm( | |
opts.erased ? lang.erase(type) : type, | |
{}, | |
{weak: false, unbox: true} | |
) | |
} | |
// Reduces a term to it's normal form using the optimal algorithm. | |
function optimal_reduce(term_or_name, defs, opts = {}) { | |
const term = name_to_term_if_not_term(term_or_name, defs); | |
let stats = opts.stats || {} | |
let net = to_net.compile(lang.erase(term, defs), defs); | |
if (stats.input_net === null) { | |
stats.input_net = clone(net); | |
} | |
if (opts.strict) { | |
net.reduce_strict(stats); | |
} else { | |
net.reduce_lazy(stats); | |
} | |
if (stats.output_net !== undefined) { | |
stats.output_net = clone(net); | |
} | |
return to_net.decompile(net); | |
} | |
// Reduces a term to it's normal form using javascript functions (beta reduction) | |
function beta_reduce(term_or_name, defs, opts = {}) { | |
const term = name_to_term_if_not_term(term_or_name, defs); | |
return to_js.decompile(to_js.compile(lang.erase(term, defs), defs)); | |
} | |
// Reduces a term to it's normal form using it's AST so it keeps more info that is useful for debug | |
// If weak is set to false, it will first try a non-weak reduction but if it fails it will fallback | |
// to a weak reduction. | |
function debug_reduce(term_or_name, defs, opts = {}) { | |
const {erased, weak, unbox, logging} = opts; | |
const term = name_to_term_if_not_term(term_or_name, defs); | |
const erased_term = erased ? lang.erase(term) : term; | |
try { | |
return lang.norm(erased_term, defs, {unbox, logging, weak}); | |
} catch (e) { | |
return lang.norm(erased_term, defs, {unbox, logging, weak: true}); | |
} | |
} | |
// Calls a formality function with a JS value using Json interop layer | |
// You can optionally specify a reducer function | |
function json_call(term_or_name, defs, argument, opts = {}) { | |
const term = name_to_term_if_not_term(term_or_name); | |
const fn_type = type(term, defs); | |
console.log(fn_type); // TODO: Check fn type | |
const argument_term = json.to(argument); | |
const reducer = opts.reducer || (term) => optimal_reduce(term, defs); | |
const app_term = lang.App(term, argument_term, false); | |
return json.from(reducer(app_term)) | |
} | |
module.exports = { | |
name_to_term, | |
type, | |
optimal_reduce, | |
beta_reduce, | |
debug_reduce, | |
json_call | |
} | |
// Private helpers | |
function name_to_term_if_not_term(term_or_name) { | |
if(typeof term_or_name === "string") { | |
return name_to_term(term_or_name); | |
} | |
return term_or_name; | |
} | |
function clone(obj) { | |
return JSON.parse(JSON.stringify(obj)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment