User:Ramcinfo/fancu staile: Difference between revisions
(→Comparison with Ross Ogilvie's system: Mr. Ogilvie removed the essay from his site (http://rossogilvie.id.au/essays/2013-01-22-fancu-bridi-mekso/), but it is archived on github) |
|||
(53 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
This is an attempt to use lojban as a functional programming language. It was in part inspired by [[Missing_predicates#List|Tsani’s recursive predicate]] and, while developed mostly independently, many things are done the same. | |||
Let us think about selbri as function taking its terbri as arguments and returning the predication, or bridi. This predication can be then claimed in context, returning truth-value of resulting bridi in that context. | Let us think about selbri as function taking its terbri as arguments and returning the predication, or bridi. This predication can be then claimed in context, returning truth-value of resulting bridi in that context. | ||
Line 12: | Line 14: | ||
We are now ready to construct functions taking functions as arguments and/or returning other functions. Let's start with ''apply'' (for unary function): | We are now ready to construct functions taking functions as arguments and/or returning other functions. Let's start with ''apply'' (for unary function): | ||
lo ka | lo goi la pliri'a ge'u ka la jalge la fancu la sumti ce'ai | ||
la jalge cu me'au la fancu la sumti kei | |||
function apply(fun, arg) { | function apply(fun, arg) { | ||
Line 20: | Line 22: | ||
Now we can use it as such: | Now we can use it as such: | ||
lo me'au | lo me'au la pliri'a me'u be me'ei tavla bei mi be'o | ||
It could be rewritten in CLL Lojban, but would be (even) less readable: | It could be rewritten in CLL Lojban, but would be (even) less readable: | ||
Line 30: | Line 32: | ||
Function composition, ''compose'' (for unary functions, still): | Function composition, ''compose'' (for unary functions, still): | ||
lo | lo goi la finti ge'u ka la jalge la fancu xipa la fancu xire ce'ai | ||
la jalge cu ka la jalge xipa la sumti ce'ai | |||
la jalge xipa cu me'au la fancu xipa lo me'au la fancu xire ku be la sumti kei kei | |||
function compose(fun, fuun) { | function compose(fun, fuun) { | ||
Line 42: | Line 44: | ||
Infinite recursion (do not try it at home): | Infinite recursion (do not try it at home): | ||
lo ka me' | lo goi la cimnrekursi ge'u ka me'au la cimnrekursi kei | ||
function infRec() { | function infRec() { | ||
Line 48: | Line 50: | ||
} | } | ||
I am not sure of the last one. Maybe {goi} works only forward in scope. {me' | I am not sure of the last one. Maybe {goi} works only forward in scope. {me'au lo ka nei} (or simply {nei}) will do almost the same, I guess. | ||
== if == | == if == | ||
Line 54: | Line 56: | ||
Confitional (taken from Tsani’s recursive predicate definition, replacing {ckaji} with {du}): | Confitional (taken from Tsani’s recursive predicate definition, replacing {ckaji} with {du}): | ||
lo ka | lo goi la cuxna ge'u ka la jalge la krinu by boi cy ce'ai | ||
ge ganai | ge ganai me'au la krinu gi la jalge cu du by | ||
gi ga | gi ga me'au la krinu gi la jalge cu du cy kei | ||
(What if replace {du} with {me'au}?) | |||
Maybe also la gleki's {ifle} will work: | Maybe also la gleki's {ifle} will work: | ||
lo goi | lo goi la cuxna ge'u ka la jalge la krinu by boi cy ce'ai | ||
la krinu cu ifle | |||
lo du'u | lo du'u la jalge cu du by kei | ||
lo du'u | lo du'u la jalge cu du cy kei kei | ||
== Recursion (again) == | == Recursion (again) == | ||
Now we are ready to build a simple recursion. {krasi} and {fanmo} are used to get first and last elements of sequence, respectively; I am not very sure if this is appropriate. | Now we are ready to build a simple recursion. {krasi} and {fanmo} are used to get first and last elements of sequence, respectively; I am not very sure if this is appropriate. Now if the style is to be developed in the direction of LISP, then functions working on sequences, like ''head'', ''tail'' and ''cons'' are to be defined. | ||
lo ka | |||
{je'abo goi} is a hack even dirtier than it is usual for these matters; it is used to both a) group the sequence as one sumti to attach relative clause to it and b) to move that clause to the front. | |||
lo sumji be li pa lo me'au | |||
be | lo goi la kancu ge'u ka la jalge la porsi la cabna ce'ai | ||
la jalge cu me'au la cuxna lo du'u la cabna cu fanmo la porsi kei li pa | |||
li ci cu me'au | lo sumji be li pa lo me'au la kancu ku | ||
be la porsi bei lo bavla'i be la cabna bei la porsi kei | |||
je'abo goi la mupli ge'u by ce'o cy ce'o dy zo'u | |||
li ci cu me'au la kancu la mupli lo krasi be la mupli | |||
// approximately | // approximately | ||
Line 81: | Line 88: | ||
assert(3 === len(sample, sample[0])); | assert(3 === len(sample, sample[0])); | ||
== curry == | |||
For now, let us pretend that we already have function for ''cons'', being {la zbasu} (x1 is sequence with head x2 and tail sequence x3. We'll also use {tersu'imei} for getting function (selbri) arity (we could use {lo se pormei be lo se zilbri be lo ka broda}, or above defined {la kancu} instead of {se pormei}). | |||
lo goi la karis. ge'u ka | |||
la jalge la fancu ce'ai | |||
lo goi la karis.xipa ge'u ka | |||
la jalge xipa la fancu xipa la terbri ce'ai | |||
la jalge xipa cu ka | |||
la jalge xire la sumti ce'ai | |||
lo goi la terbri xipa ge'u poi'i | |||
ke'a me'au la zbasu me'u la sumti la terbri kei zo'u | |||
la jalge xire cu me'au la cuxna me'u | |||
lo du'u lo se tersu'imei be la fancu xipa cu dubdu'i | |||
lo se pormei be la terbri xipa kei | |||
lo poi'i ke'a bridi la fancu xipa la terbri xipa kei | |||
lo poi'i ke'a me'au la karis.xipa me'u la fancu xipa la terbri xipa kei kei kei zo'u | |||
la jalge cu me'au la karis.xipa me'u la fancu lo kutpoi kei | |||
function curry(fun) { | |||
function curry1(fun, args) { | |||
return function (arg) { | |||
var args1 = args; | |||
args1.unshift(arg); | |||
if (fun.length == args1.length) { | |||
return fun(args1) | |||
} else { | |||
return curry1(fun, args1); | |||
} | |||
} | |||
} | |||
return curry1(fun, []); | |||
} | |||
Usage: | |||
la fanxu xinu cu me'au la karis. me'u la fancu | |||
.i la fanxu xipu cu me'au la fancu xinu me'u li pu | |||
.i la fanxu xire cu me'au la fancu xipu me'u li re | |||
.i la jalge cu me'au la fanxu xire me'u li ci | |||
var curriedFun = curry(fun); | |||
var curriedFun1 = curriedFun(1); | |||
var curriedFun2 = curriedFun(2); | |||
var result = curriedFun(3); | |||
Practical (hehe...) example: | |||
la klesi xiky cu me'au la karis. me'u me'ei setese klesi // var curriedFilter = curry(filter); | |||
.i la xunre xiky cu me'au la klesi xiky me'u lo ka xunre // var redFilter = curriedFilter(red); | |||
.i la jalge xipu cu me'au la xunre xiky me'u lo seltadni xipu // var result1 = redFilter(sample1); | |||
.i la jalge xipu cu me'au la xunre xiky me'u lo seltadni xire // var result2 = redFilter(sample2); | |||
In effect, we reinvented {ka}: | |||
lo goi la xunre xiky ge'u ka [ce'u] klesi [ce'u] fi lo ka xunre kei kei | |||
// var redFilter = function (sample) { return filter(sample, red); }; | |||
Conditional could be rewritten shorter, but more cryptically (as this style is new): | |||
lo ''goi'' <u>la karis.</u> ''ge'u'' ka | |||
<u>la jalge</u> <u>la fancu</u> ce'ai | |||
lo ''goi'' <u>la karis.xipa</u> ''ge'u'' ka | |||
<u>la jalge xipa</u> <u>la fancu xipa</u> <u>la terbri</u> ce'ai | |||
<u>la jalge xipa</u> cu ka | |||
<u>la jalge xire</u> <u>la sumti</u> ce'ai | |||
lo ''goi'' <u>la terbri xipa</u> ''ge'u'' poi'i | |||
ke'a ''me'au'' <u>la zbasu</u> ''me'u'' <u>la sumti</u> <u>la terbri</u> kei zo'u | |||
<u>la jalge xire</u> cu ''me'au'' lo ''me'au'' <u>la cunxa</u> ''me'u'' | |||
lo du'u lo se tersu'imei be <u>la fancu xipa</u> cu dubdu'i | |||
lo se pormei be <u>la terbri xipa</u> kei | |||
me'ei bridi <u>la karis.xipa</u> me'u <u>la fancu xipa</u> <u>la terbri xipa</u> kei kei zo'u | |||
<u>la jalge</u> cu ''me'au'' <u>la karis.xipa</u> ''me'u'' <u>la fancu</u> lo kutpoi kei | |||
//function apply(fun, args) {return fun.apply(this, args); } | |||
function curry(fun) { | |||
function curry1(fun, args) { | |||
return function (arg) { | |||
var args1 = args; | |||
args1.unshift(arg); | |||
return ((fun.length == args1.length) ? apply : curry1)(fun, args1); | |||
} | |||
} | |||
return curry1(fun, []); | |||
} | |||
== Notes == | |||
For conversion between predicate taking sequence as argument and n-ary predicate, {brije'u} (alias {zilbri}) is most natural way: | |||
a'y konkatena byboi cyboi dyboi ... ≡ me'ei konkatena cu brije'u a'y ce'o by ce'o cy ce'o dy ... | |||
Various ways to call a function: | |||
'''lo''' me'au la ''fancu'' me'u '''be''' ''la sumti'' '''bei''' ''la sumti'' '''be'o''' | |||
'''lo poi'i ke'a''' me'au la ''fancu'' me'u ''la sumti'' ''la sumti'' '''kei''' | |||
'''lo kai'u ce'u''' me'au la ''fancu'' me'u ''la sumti'' ''la sumti'' '''kei''' | |||
'''lo'oi ke'a''' me'au la ''fancu'' me'u ''la sumti'' ''la sumti'' '''ku'au''' | |||
Or with {emna}: | |||
'''lo''' se.emna '''be''' la ''fancu'' '''bei''' ''la sumti'' '''bei''' ''la sumti'' '''be'o''' | |||
'''lo poi'i ke'a''' se.emna la ''fancu'' ''la sumti'' ''la sumti'' '''kei''' | |||
'''lo kai'u ce'u''' se.emna la ''fancu'' ''la sumti'' ''la sumti'' '''kei''' | |||
'''lo'oi ke'a''' se.emna la ''fancu'' ''la sumti'' ''la sumti'' '''ku'au''' | |||
== Comparison with Ross Ogilvie's system == | |||
Ross Ogilvie presents a proposal for reformation of mex<ref>https://github.com/RossOgilvie/essays/blob/master/fancu%20bridi%20mekso.html</ref> with some very similar ideas. Here's comparation of his notation with one used here: | |||
{| class="wikitable" | |||
|+ fancu staile/fancu bridi mekso comparison | |||
! operation !! Ramcinfo !! Ross Ogilvie | |||
|- | |||
| return value || no special notation<sup>*</sup>, ce'u, ke'a || ce'au<sup>‡</sup> | |||
|- | |||
| variable binding || ce'ai<sup>†</sup> || zo'ai<sup>‡</sup> ({ce'ai} is also considered) | |||
|- | |||
| convert function bridi (definition) to sumti (first-class function value) || lo ka || xau<sup>‡</sup> ({ni}, {du'u} and {su'u} are also considered) | |||
|- | |||
| convert function bridi to sumti (result of function application) || lo kai'u<sup>†</sup> (ce'u) / lo'oi<sup>†</sup> (ke'a) || also {xau} | |||
|- | |||
| convert function selbri to sumti (using functions as arguments) || me'ei<sup>†</sup> || ni'e | |||
|- | |||
| convert function sumti to selbri || me'au<sup>†</sup> || me | |||
|- | |||
| partial application || kai'u<sup>†</sup> || be'ei<sup>‡</sup> | |||
|- | |||
| function composition || la finti<sup>‡</sup> || fancyjo'e<sup>‡</sup> | |||
|- | |||
| curry || la karis.<sup>‡</sup> || na'u<sup>‡</sup> | |||
|- | |||
| uncurry || - || nu'a<sup>‡</sup> | |||
|- | |||
| list constructor || la zbasu<sup>‡</sup> || ce'o | |||
|- | |||
| map || - || porkanji<sup>‡</sup> | |||
|- | |||
| fold || - || porjmina<sup>‡</sup> | |||
|- | |||
| filter || klesi || - | |||
|} | |||
<sup>*</sup> {la jalge} is used for an bound variable argument intended as a return value, but that's pure convention. In Ramcinfo's approach, any bound variable of selbri could be used as argument or return value as needed. | |||
<sup>†</sup> Experimental | |||
<sup>‡</sup> Proposed or re-purposed specially for use in these systems | |||
== buboi == | |||
In the first version of this draft, {cizra} consctruction {<u>NAME buboi</u>} was used for variable names. It was a hack, but I knew no better way to assign more-or-less meaningful names to assignable variables. Without {buboi}, I'd be up to my neck in {ko'a}s. Luckily, la menli proposed assigning values with {goi} to cmene. Though {goi} behavior is not fully standardized <ref>http://mw.lojban.org/papri/Lojban_application_issues</ref>, I consisently place name to be assigned after it, and value being assigned before. | |||
[[Image:aulbuboi.jpg|thumb|100px| ]] | [[Image:aulbuboi.jpg|thumb|100px| ]] | ||
== References == | |||
<references/> |
Latest revision as of 10:35, 15 July 2016
This is an attempt to use lojban as a functional programming language. It was in part inspired by Tsani’s recursive predicate and, while developed mostly independently, many things are done the same.
Let us think about selbri as function taking its terbri as arguments and returning the predication, or bridi. This predication can be then claimed in context, returning truth-value of resulting bridi in that context.
function tavla(speaker, listener, subject, language) {...} // returns predication function claim(predication, context) {...} // returns boolean claim(tavla("me", "you", "lojban", "lojban"), context);
To build functions returning other things, we can use {lo}. Let us not go into intricacies of descriptors and pretend what {lo selbri} returns simply some value s1 such that claim(selbri(s1, s2...sx), context) will be true for some values of s2...sx and claimed with some context. Arguments other than context could be restricted with {be...bei...be'o}. So {lo selbri be sumti2 bei sumti3 be'o} is x1 = selbri1(sumti2, sumti3).
{loka}- and {me'ei}-abstractions, then, are predication-returning functions as first-class values. {me'au} with these abstractions is function application; {kai'u} is immediate function application.
apply
We are now ready to construct functions taking functions as arguments and/or returning other functions. Let's start with apply (for unary function):
lo goi la pliri'a ge'u ka la jalge la fancu la sumti ce'ai la jalge cu me'au la fancu la sumti kei
function apply(fun, arg) { return fun(arg); }
Now we can use it as such:
lo me'au la pliri'a me'u be me'ei tavla bei mi be'o
It could be rewritten in CLL Lojban, but would be (even) less readable:
cylylypapi'epa jo'au lo ka bridi ce'u ce'u ce'o ce'u kei goi ko'a zo'u co'e zo'e poi bridi be ko'a bei lo ka ce'u tavla ce'u ku ce'o ke'a ce'o mi
compose
Function composition, compose (for unary functions, still):
lo goi la finti ge'u ka la jalge la fancu xipa la fancu xire ce'ai la jalge cu ka la jalge xipa la sumti ce'ai la jalge xipa cu me'au la fancu xipa lo me'au la fancu xire ku be la sumti kei kei
function compose(fun, fuun) { return function (arg) { return fun(fuun(arg)); }}
Recursion
Infinite recursion (do not try it at home):
lo goi la cimnrekursi ge'u ka me'au la cimnrekursi kei
function infRec() { infRec(); }
I am not sure of the last one. Maybe {goi} works only forward in scope. {me'au lo ka nei} (or simply {nei}) will do almost the same, I guess.
if
Confitional (taken from Tsani’s recursive predicate definition, replacing {ckaji} with {du}):
lo goi la cuxna ge'u ka la jalge la krinu by boi cy ce'ai ge ganai me'au la krinu gi la jalge cu du by gi ga me'au la krinu gi la jalge cu du cy kei
(What if replace {du} with {me'au}?) Maybe also la gleki's {ifle} will work:
lo goi la cuxna ge'u ka la jalge la krinu by boi cy ce'ai la krinu cu ifle lo du'u la jalge cu du by kei lo du'u la jalge cu du cy kei kei
Recursion (again)
Now we are ready to build a simple recursion. {krasi} and {fanmo} are used to get first and last elements of sequence, respectively; I am not very sure if this is appropriate. Now if the style is to be developed in the direction of LISP, then functions working on sequences, like head, tail and cons are to be defined.
{je'abo goi} is a hack even dirtier than it is usual for these matters; it is used to both a) group the sequence as one sumti to attach relative clause to it and b) to move that clause to the front.
lo goi la kancu ge'u ka la jalge la porsi la cabna ce'ai la jalge cu me'au la cuxna lo du'u la cabna cu fanmo la porsi kei li pa lo sumji be li pa lo me'au la kancu ku be la porsi bei lo bavla'i be la cabna bei la porsi kei je'abo goi la mupli ge'u by ce'o cy ce'o dy zo'u li ci cu me'au la kancu la mupli lo krasi be la mupli
// approximately function len(list, item) { return (list.indexOf(item) === list.length - 1) ? 1 : 1 + len(list, list[list.indexOf(item)] + 1); } var sample = ["b", "c", "d"]; assert(3 === len(sample, sample[0]));
curry
For now, let us pretend that we already have function for cons, being {la zbasu} (x1 is sequence with head x2 and tail sequence x3. We'll also use {tersu'imei} for getting function (selbri) arity (we could use {lo se pormei be lo se zilbri be lo ka broda}, or above defined {la kancu} instead of {se pormei}).
lo goi la karis. ge'u ka la jalge la fancu ce'ai lo goi la karis.xipa ge'u ka la jalge xipa la fancu xipa la terbri ce'ai la jalge xipa cu ka la jalge xire la sumti ce'ai lo goi la terbri xipa ge'u poi'i ke'a me'au la zbasu me'u la sumti la terbri kei zo'u la jalge xire cu me'au la cuxna me'u lo du'u lo se tersu'imei be la fancu xipa cu dubdu'i lo se pormei be la terbri xipa kei lo poi'i ke'a bridi la fancu xipa la terbri xipa kei lo poi'i ke'a me'au la karis.xipa me'u la fancu xipa la terbri xipa kei kei kei zo'u la jalge cu me'au la karis.xipa me'u la fancu lo kutpoi kei
function curry(fun) { function curry1(fun, args) { return function (arg) { var args1 = args; args1.unshift(arg); if (fun.length == args1.length) { return fun(args1) } else { return curry1(fun, args1); } } } return curry1(fun, []); }
Usage:
la fanxu xinu cu me'au la karis. me'u la fancu .i la fanxu xipu cu me'au la fancu xinu me'u li pu .i la fanxu xire cu me'au la fancu xipu me'u li re .i la jalge cu me'au la fanxu xire me'u li ci
var curriedFun = curry(fun); var curriedFun1 = curriedFun(1); var curriedFun2 = curriedFun(2); var result = curriedFun(3);
Practical (hehe...) example:
la klesi xiky cu me'au la karis. me'u me'ei setese klesi // var curriedFilter = curry(filter); .i la xunre xiky cu me'au la klesi xiky me'u lo ka xunre // var redFilter = curriedFilter(red); .i la jalge xipu cu me'au la xunre xiky me'u lo seltadni xipu // var result1 = redFilter(sample1); .i la jalge xipu cu me'au la xunre xiky me'u lo seltadni xire // var result2 = redFilter(sample2);
In effect, we reinvented {ka}:
lo goi la xunre xiky ge'u ka [ce'u] klesi [ce'u] fi lo ka xunre kei kei // var redFilter = function (sample) { return filter(sample, red); };
Conditional could be rewritten shorter, but more cryptically (as this style is new):
lo goi la karis. ge'u ka la jalge la fancu ce'ai lo goi la karis.xipa ge'u ka la jalge xipa la fancu xipa la terbri ce'ai la jalge xipa cu ka la jalge xire la sumti ce'ai lo goi la terbri xipa ge'u poi'i ke'a me'au la zbasu me'u la sumti la terbri kei zo'u la jalge xire cu me'au lo me'au la cunxa me'u lo du'u lo se tersu'imei be la fancu xipa cu dubdu'i lo se pormei be la terbri xipa kei me'ei bridi la karis.xipa me'u la fancu xipa la terbri xipa kei kei zo'u la jalge cu me'au la karis.xipa me'u la fancu lo kutpoi kei
//function apply(fun, args) {return fun.apply(this, args); } function curry(fun) { function curry1(fun, args) { return function (arg) { var args1 = args; args1.unshift(arg); return ((fun.length == args1.length) ? apply : curry1)(fun, args1); } } return curry1(fun, []); }
Notes
For conversion between predicate taking sequence as argument and n-ary predicate, {brije'u} (alias {zilbri}) is most natural way:
a'y konkatena byboi cyboi dyboi ... ≡ me'ei konkatena cu brije'u a'y ce'o by ce'o cy ce'o dy ...
Various ways to call a function:
lo me'au la fancu me'u be la sumti bei la sumti be'o
lo poi'i ke'a me'au la fancu me'u la sumti la sumti kei
lo kai'u ce'u me'au la fancu me'u la sumti la sumti kei
lo'oi ke'a me'au la fancu me'u la sumti la sumti ku'au
Or with {emna}:
lo se.emna be la fancu bei la sumti bei la sumti be'o
lo poi'i ke'a se.emna la fancu la sumti la sumti kei
lo kai'u ce'u se.emna la fancu la sumti la sumti kei
lo'oi ke'a se.emna la fancu la sumti la sumti ku'au
Comparison with Ross Ogilvie's system
Ross Ogilvie presents a proposal for reformation of mex[1] with some very similar ideas. Here's comparation of his notation with one used here:
operation | Ramcinfo | Ross Ogilvie |
---|---|---|
return value | no special notation*, ce'u, ke'a | ce'au‡ |
variable binding | ce'ai† | zo'ai‡ ({ce'ai} is also considered) |
convert function bridi (definition) to sumti (first-class function value) | lo ka | xau‡ ({ni}, {du'u} and {su'u} are also considered) |
convert function bridi to sumti (result of function application) | lo kai'u† (ce'u) / lo'oi† (ke'a) | also {xau} |
convert function selbri to sumti (using functions as arguments) | me'ei† | ni'e |
convert function sumti to selbri | me'au† | me |
partial application | kai'u† | be'ei‡ |
function composition | la finti‡ | fancyjo'e‡ |
curry | la karis.‡ | na'u‡ |
uncurry | - | nu'a‡ |
list constructor | la zbasu‡ | ce'o |
map | - | porkanji‡ |
fold | - | porjmina‡ |
filter | klesi | - |
* {la jalge} is used for an bound variable argument intended as a return value, but that's pure convention. In Ramcinfo's approach, any bound variable of selbri could be used as argument or return value as needed.
† Experimental
‡ Proposed or re-purposed specially for use in these systems
buboi
In the first version of this draft, {cizra} consctruction {NAME buboi} was used for variable names. It was a hack, but I knew no better way to assign more-or-less meaningful names to assignable variables. Without {buboi}, I'd be up to my neck in {ko'a}s. Luckily, la menli proposed assigning values with {goi} to cmene. Though {goi} behavior is not fully standardized [2], I consisently place name to be assigned after it, and value being assigned before.