mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-10 06:54:04 +09:00
basic: currying is now operator & does not require special treatment on tree execution
This commit is contained in:
@@ -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}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user