basic: currying is now operator & does not require special treatment on tree execution

This commit is contained in:
minjaesong
2020-12-22 17:21:42 +09:00
parent d785ecf568
commit 2f054b9c67
11 changed files with 308 additions and 308 deletions

View File

@@ -15,13 +15,13 @@ There are six basic types: \emph{number}, \emph{boolean}, \emph{string}, \emph{
\emph{Boolean} is the type of the values that is either \codebf{TRUE} or \codebf{FALSE}. Number \codebf{0} and \codebf{FALSE} makes condition \emph{false}. When used in numeric context, \codebf{FALSE} will be interpreted as 0 and \codebf{TRUE} as 1.
\emph{String} represents immutable\footnote{cannot be altered directly} sequences of bytes. However, you can't weave them to make something like \emph{string array}\footnote{future feature\ldots maybe\ldots? Probably not\ldots}.
\emph{String} represents immutable\footnote{cannot be altered directly} sequences of bytes. However, you can't weave them to make something like \emph{string array}\footnote{future feature\ldots\ maybe\ldots? Probably not\ldots}.
\emph{Array} represents collection of numbers in 1- or more dimensions.
\emph{Generator} represents a value that automatically counts up/down whenever they have been called in For-Next loop.
\emph{Functions} are, well\ldots functions\footnote{This is not a closure; there is no way you can define a local- or anonymous variable in BASIC.}, especially user-defined ones. Functions are \emph{type} because some built-in functions will actually take \emph{functions} as arguments.
\emph{Functions} are, well\ldots\ functions\footnote{This is not a closure; there is no way you can define a local- or anonymous variable in BASIC.}, especially user-defined ones. Functions are \emph{type} because some built-in functions will actually take \emph{functions} as arguments.
\section{Control Flow}

View File

@@ -39,12 +39,13 @@ So what the fsck is currying? Consider the following code:
\begin{lstlisting}
10 DEFUN F(K,T)=ABS(T)==K
20 CF=CURRY(F,32)
20 CF=F<~32
30 PRINT CF(24) : REM will print 'false'
40 PRINT CF(-32) : REM will print 'true'
\end{lstlisting}
Here, \code{CF} is a curried function of \code{F}; built-in function \code{CURRY} applies \code{32} to the first parametre of the function \code{F}, which dynamically returns a \emph{function} of \code{CF(T) = ABS(T) == 32}. The fact that \code{CURRY} returns a \emph{function} opens many possibilities, for example, you can create loads of sibling functions without making loads of duplicate codes.
% NOTE: you can't use \basiccurry within \code{}
Here, \code{CF} is a curried function of \code{F}; built-in operator \code{$<\!\sim$} applies \code{32} to the first parameter of the function \code{F}, which dynamically returns a \emph{function} of \code{CF(T) = ABS(T) == 32}. The fact that Curry Operator returns a \emph{function} opens many possibilities, for example, you can create loads of sibling functions without making loads of duplicate codes.
\section[Wrapping-Up]{The Grand Unification}
@@ -53,21 +54,21 @@ Using all the knowledge we have learned, it should be trivial\footnote{/s} to wr
\begin{lstlisting}
10 DEFUN LESS(P,X)=X<P
11 DEFUN GTEQ(P,X)=X>=P
12 DEFUN QSORT(XS)=IF LEN(XS)<1 THEN NIL ELSE
QSORT(FILTER(CURRY(LESS,HEAD XS),TAIL XS)) # HEAD(XS)!NIL #
QSORT(FILTER(CURRY(GTEQ,HEAD XS),TAIL XS))
12 DEFUN QSORT(XS)=IF LEN(XS)<1 THEN NIL ELSE
QSORT(FILTER(LESS<~HEAD(XS),TAIL(XS))) # HEAD(XS)!NIL #
QSORT(FILTER(GTEQ<~HEAD(XS),TAIL(XS)))
100 L=7!9!4!5!2!3!1!8!6!NIL
110 SL=QSORT(L)
120 PRINT L:PRINT SL
110 PRINT L
120 PRINT QSORT(L)
\end{lstlisting}
Line 12 implements quicksort algorithm, using \code{LESS} and \code{GTEQ} as helper functions. \code{LESS} is a user-function version of less-than operator, and \code{GTEQ} is similar. \code{QSORT} selects a pivot using head-element of array \code{XS}\footnote{stands for \emph{X's}} using \code{HEAD XS}, then using curried version of \code{LESS} and \code{GTEQ} to move values lesser than pivot \emph{minus the head element (here \code{TAIL XS} returns such array)} to the left and greater to the right, and these two sorted \emph{chunks} are recursively sorted using the same \code{QSORT} function. Currying is used to give comparison functions a pivot-value to compare against, and also because \code{FILTER} wants a \emph{function} and not an \emph{expression}. \code{HEAD XS} simply fetches a head-elemement of \code{XS}. \code{HEAD(XS)!NIL} creates a single-element array contains \code{XS(0)}.
%Uncomment this if you finally decided to support a closure%
Using \emph{closure}, the definition of \code{QSORT} can truly be a one-liner and be \emph{even more cryptic}:
\begin{lstlisting}
10 DEFUN QSORT(XS)=IF LEN(XS)<1 THEN NIL ELSE
QSORT(FILTER([K]~>K<HEAD XS,TAIL XS)) # HEAD(XS)!NIL #
QSORT(FILTER([K]~>K>=HEAD XS,TAIL XS))
\end{lstlisting}
%% Using \emph{closure}, the definition of \code{QSORT} can truly be a one-liner and be \emph{even more cryptic}:
%%
%% \begin{lstlisting}
%% 10 QSORT=[XS]~>IF LEN(XS)<1 THEN NIL ELSE
%% QSORT(FILTER([K]~>K<HEAD XS,TAIL XS)) # HEAD(XS)!NIL #
%% QSORT(FILTER([K]~>K>=HEAD XS,TAIL XS))
%% \end{lstlisting}

View File

@@ -72,13 +72,11 @@ Furthermore, \emph{sigils} are not used in the \tbas{} and attempting to use one
Types of data recognised by \tbas{} are distinguished by some arcane magic of Javascript auto-casing mumbo-jumbo
\begin{tabulary}{\textwidth}{RCL}
\begin{tabulary}{\textwidth}{rCL}
Type & Range & Precision \\
\hline \hline
\hline
String & As many as the machine can handle & \, \\
\hline
Integer & $ \pm 2^{53}-1 $ & exact within the range \\
\hline
Float & $ \pm 4.9406564584124654 \times 10^{-324} $ -- $ \pm 1.7976931348623157 \times 10^{308} $ & about 16 significant figures \\
\end{tabulary}
@@ -87,21 +85,22 @@ Float & $ \pm 4.9406564584124654 \times 10^{-324} $ -- $ \pm 1.7976931348623157
The order of precedence of the operators is as shown below, lower numbers means they have higher precedence (more tightly bound)
\begin{tabulary}{\textwidth}{CCC|CCC}
Precedence & Operators & Associativity & Precedence & Operators & Associativity \\
\begin{tabulary}{\textwidth}{cCc|cCc}
Order & Op & Associativity & Order & Op & Associativity \\
\hline
1 & \basicexp & Right & 10 & \condensedfont{BAND} & Left \\
2 & \ast \quad $/$ \quad $\backslash$ & Left & 11 & \condensedfont{BXOR} & Left \\
3 & \condensedfont{MOD} & Left & 12 & \condensedfont{BOR} & Left \\
4 & $+$ \quad $-$ & Left & 13 & \condensedfont{AND} & Left \\
5 & \condensedfont{NOT} \enskip \condensedfont{BNOT} & Left & 14 & \condensedfont{OR} & Left \\
6 & <\!< \quad >\!> & Left & 15 & \condensedfont{TO} \enskip \condensedfont{STEP} & Left \\
7 & < \enskip > \enskip <\!= \enskip =\!< \enskip >\!= \enskip =\!> & Left & 16 & ! & Right \\
8 & == \quad <\!> \quad >\!< & Left & 17 & \sim & Left\\
9 & \condensedfont{MIN} \enskip \condensedfont{MAX} & Left & 18 & \# & Left \\
& & & 19 & = & Right \\
1 & \basicexp & Right & 11 & \condensedfont{BXOR} & Left \\
2 & \ast \quad $/$ \quad $\backslash$ & Left & 12 & \condensedfont{BOR} & Left \\
3 & \condensedfont{MOD} & Left & 13 & \condensedfont{AND} & Left \\
4 & $+$ \quad $-$ & Left & 14 & \condensedfont{OR} & Left \\
5 & \condensedfont{NOT} \enskip \condensedfont{BNOT} & Left & 15 & \condensedfont{TO} \enskip \condensedfont{STEP} & Left \\
6 & <\!< \quad >\!> & Left & 16 & ! & Right \\
7 & < \enskip > \enskip <\!= \enskip =\!< \enskip >\!= \enskip =\!> & Left & 17 & \sim & Left\\
8 & == \quad <\!> \quad >\!< & Left & 18 & \# & Left \\
9 & \condensedfont{MIN} \enskip \condensedfont{MAX} & Left & 19 & \basiccurry & Right \\
10 & \condensedfont{BAND} & Left & 20 & = & Right \\
\end{tabulary}
\subsubsection*{Examples}
\begin{itemlist}
\item Exponentiation is more tightly bound than negation: \code{-1\basicexp 2 == -(1\basicexp 2) == -1} but \code{(-1)\basicexp 2 == 1}
@@ -112,7 +111,7 @@ Precedence & Operators & Associativity & Precedence & Operators & Associativity
Mathematical operators operate on expressions that returns numeric value only, except for the \code{+} operator which will take the action of string concatenation if either of the operand is non-numeric.
\begin{tabulary}{\textwidth}{CLL}
\begin{tabulary}{\textwidth}{clL}
Code & Operation & Result \\
\hline
\emph{x} $=$ \emph{y} & Assignment & Assigns \emph{y} into \emph{x} \\
@@ -146,7 +145,7 @@ $-$ \emph{x} & Unary Minus & Negative value of \emph{x} \\
Comparison operator can operate on numeric and string operands. String operands will be automatically converted to numeric value if they can be; if one operand is numeric and other is non-numeric string, the former will be converted to string value.
\begin{tabulary}{\textwidth}{CLL}
\begin{tabulary}{\textwidth}{clL}
Code & Operation & Result \\
\hline
\emph{x} == \emph{y} & Equal & True if \emph{x} equals \emph{y} \\
@@ -169,7 +168,7 @@ When comparing strings, the ordering is as follows:
Bitwise operators operate on unsigned integers only. Floating points are truncated\footnote{truncated towards zero} to integers.
\begin{tabulary}{\textwidth}{CLL}
\begin{tabulary}{\textwidth}{clL}
Code & Operation & Result \\
\hline
\emph{x} <\!< \emph{y} & Bitwise Shift Left & Shifts entire bits of \emph{x} by \emph{y} \\
@@ -184,7 +183,7 @@ Code & Operation & Result \\
Boolean operators operate on boolean values. If one of the operand is not boolean, it will be cast to appropriate boolean value. See \ref{valuesandtypes} for casting rules.
\begin{tabulary}{\textwidth}{CLL}
\begin{tabulary}{\textwidth}{clL}
Code & Operation & Result \\
\hline
\condensedfont{NOT} \emph{x} & Logical negation & True if \emph{x} is false and vice versa \\
@@ -196,7 +195,7 @@ Code & Operation & Result \\
Generator operators operate on numeric values and generators to create and modify a generator.
\begin{tabulary}{\textwidth}{CLL}
\begin{tabulary}{\textwidth}{clL}
Code & Result \\
\hline
\emph{x} \condensedfont{TO} \emph{y} & Creates an generator that counts from \emph{x} to \emph{y} \\
@@ -207,7 +206,7 @@ Code & Result \\
Array operators operate on arrays and numeric values.
\begin{tabulary}{\textwidth}{CLL}
\begin{tabulary}{\textwidth}{clL}
Code & Operation & Result \\
\hline
\emph{x} $!$ \emph{y} & Cons & Prepends a value of \emph{x} into an array of \emph{y} \\
@@ -217,6 +216,17 @@ Code & Operation & Result \\
Arbitrary arrays can be constructed using empty-array constant \codebf{NIL}.
\subsection{Function Operators}
Function operators operate on functions and some values.
\begin{tabulary}{\textwidth}{clL}
Code & Operation & Result \\
\hline
\emph{f} \basiccurry{} \emph{x} & Curry & Apply \emph{x} into the first parameter of the function \emph{f} \\
%{[}\emph{x},\,\emph{y}\ldots{]} \basicclosure{} \emph{e} & Closure & Creates a closure (anonymous function) from one or more parameters \emph{x},\,\emph{y}\ldots\ and an expression \emph{e} \\
\end{tabulary}
\section{Syntax In EBNF}
If you're \emph{that} into the language theory of computer science, texts above are just waste of bytes/inks/pixel-spaces/whatever; this little section should be more than enough!

View File

@@ -22,7 +22,7 @@ If \code{TRUTH\_VALUE} is truthy, executes \code{TRUE\_EXPRESSION}; if \code{TRU
Jumps to \code{INDEX\_EXPRESSION}-th line number in the argements. If \code{INDEX\_EXPRESSION} is outside of range of the arguments, no jump will be performed.
\subsubsection*{Parametres}
\subsubsection*{parameters}
\begin{itemlist}
\item \code{LINEn} can be a number, numeric expression (aka equations) or a line label.
@@ -39,7 +39,7 @@ With the aid of other statements\footnote{Actually, only the IF is useful, unles
Oh, and you can define your own function, in traditional \code{DEF FN} sense.
\subsubsection*{Parametres}
\subsubsection*{parameters}
\begin{itemlist}
\item \code{NAME} must be a valid variable name

View File

@@ -51,11 +51,15 @@
\newenvironment{itemlist}{\vspace{0pt}\itemize}{\enditemize}
%% Idioms %%
\hyphenation{Java-scr-ipt}
\hyphenation{ECMA-scr-ipt}
\hyphenation{Java-script}
\hyphenation{ECMA-script}
\newcommand\forceindent{\hskip1.5em}
%% BASIC operators %%
\newcommand\basicexp{\raisebox{0.25ex}{\scriptsize\wedge}}
\newcommand\basiccurry{$<\!\sim$}
\newcommand\basicclosure{$\sim\!>$}
% Title styling
\pretitle{\begin{flushright}}
@@ -71,6 +75,9 @@
\setbeforesubsecskip{\mytextsize}
\setbeforesubsubsecskip{\mytextsize}
% extra space for table
\setlength{\extrarowheight}{0.166ex}
% chapter title -- no now page after
\renewcommand\chapterheadstart{} % kill the drop
\renewcommand\afterchapternum{\vskip 0.5em} % space between number and title

View File

@@ -748,10 +748,12 @@ bF._opPrc = {
"STEP":41,
"!":50,"~":51, // array CONS and PUSH
"#": 52, // array concat
"<~": 100, // curry operator
"~>": 101, // closure operator
"=":999,
"IN":1000
};
bF._opRh = {"^":1,"=":1,"!":1,"IN":1};
bF._opRh = {"^":1,"=":1,"!":1,"IN":1,"<~":1,"~>":1};
let bStatus = {};
bStatus.builtin = {};
["PRINT","NEXT","SPC","CHR","ROUND","SQR","RND","GOTO","GOSUB","DEFUN","FOR","MAP"].forEach(w=>{ bStatus.builtin[w] = 1 });
@@ -826,10 +828,14 @@ let states15 = ["lit","lit","paren","lit","sep","num","op","num","paren"];
let tokens16 = ["DEFUN","KA","(","X",")","=","IF","X",">","2","THEN","DO","(","PRINT","(","HAI",")",";","PRINT","(","X",")",")","ELSE","DO","(","PRINT","(","BYE",")",";","PRINT","(","X",")",")"];
let states16 = ["lit","lit","paren","lit","paren","op","lit","lit","op","num","lit","lit","paren","lit","paren","qot","paren","sep","lit","paren","lit","paren","paren","lit","lit","paren","lit","paren","qot","paren","sep","lit","paren","lit","paren","paren"];
// FILTER(FN<~HEAD XS, TAIL XS)
let tokens17 = ["FILTER","(","FN","<~","HEAD","XS",",","TAIL","XS",")"];
let states17 = ["lit","paren","lit","op","lit","lit","sep","lit","lit","paren"];
try {
let trees = bF._parseTokens(lnum,
tokens16,
states16
tokens17,
states17
);
trees.forEach((t,i) => {
serial.println("\nParsed Statement #"+(i+1));