Browse Source

change structure

main
zapashcanon 1 year ago
parent
commit
8c91224895
Signed by: zapashcanon GPG Key ID: 8981C3C62D1D28F1
  1. 42
      .ocamlformat
  2. 77
      src/CODE.md
  3. 134
      src/article.tex
  4. 88
      src/bib.bib
  5. 98
      src/dune
  6. 71
      src/figures.ml
  7. 5
      src/get_style_def.py
  8. 4
      src/layout.py
  9. 15
      src/list.c
  10. 13
      src/list.d
  11. 37
      src/packages.tex
  12. 19
      src/ral.rs

42
.ocamlformat

@ -0,0 +1,42 @@
version=0.24.1
assignment-operator=end-line
break-cases=fit
break-fun-decl=wrap
break-fun-sig=wrap
break-infix=wrap
break-infix-before-func=false
break-separators=before
break-sequences=true
cases-exp-indent=2
cases-matching-exp-indent=normal
doc-comments=before
doc-comments-padding=2
doc-comments-tag-only=default
dock-collection-brackets=false
exp-grouping=preserve
field-space=loose
if-then-else=compact
indicate-multiline-delimiters=space
indicate-nested-or-patterns=unsafe-no
infix-precedence=indent
leading-nested-match-parens=false
let-and=sparse
let-binding-spacing=compact
let-module=compact
margin=80
max-indent=68
module-item-spacing=sparse
ocp-indent-compat=false
parens-ite=false
parens-tuple=always
parse-docstrings=true
sequence-blank-line=preserve-one
sequence-style=terminator
single-case=compact
space-around-arrays=true
space-around-lists=true
space-around-records=true
space-around-variants=true
type-decl=sparse
wrap-comments=false
wrap-fun-args=true

77
src/CODE.md

@ -2,44 +2,85 @@
<!-- $MDX file=list.c -->
```c
extern void exit(int);
// asking for an int version
#define TYPE int
#define TYPED(X) int_##X
// generic code
struct TYPED(list) {
TYPE head;
struct TYPED(list) *tail;
struct TYPED(list) * tail;
};
TYPE hd(struct TYPED(list) *l) {
if (l) {
return l->head;
}
exit(42);
TYPE hd(struct TYPED(list) * l) {
if (l) { return l->head; }
_Exit(42);
}
```
```sh
$ cpp -P list.c
extern void exit(int);
struct int_list {
int head;
struct int_list *tail;
struct int_list * tail;
};
int hd(struct int_list *l) {
if (l) {
return l->head;
}
exit(42);
int hd(struct int_list * l) {
if (l) { return l->head; }
_Exit(42);
}
```
```sh
$ gcc -c list.c
```
# D String Mixins
<!-- $MDX file=list.d -->
```d
template GenList(string Type) {
const char[] GenList =
"struct List_" ~ Type ~ " {\n" ~
" " ~ Type ~ " head;\n" ~
" " ~ "List_" ~ Type ~ "* tail;\n" ~
"}\n" ~
Type ~ " hd(List_" ~ Type ~ "* l) {\n" ~
" if (l) { return l.head; }\n" ~
" assert(0);\n" ~
"}";
}
mixin(GenList!("int"));
```
```sh
$ gdc -c list.d -fsave-mixins=/dev/stdout
// expansion at list.d:13:1
struct List_int {
int head;
List_int* tail;
}
int hd(List_int* l) {
if (l) { return l.head; }
assert(0);
}
```
```sh
$ gdc -c list_int.d
```
<!-- $MDX file=layout.py -->
```python
array1 = [1, 2, 3]
array2 = [42, 99, 500]
pair = (array1, array2)
```
```sh
$ python layout.py
```

134
src/article.tex

@ -1,12 +1,50 @@
\section{Introduction}
\paragraph{} A function is said to be \emph{polymorphic} when a single implementation of this function can be used with several different types. A polymorphic function may accept types that need to be treated differently at runtime. It could be because they have different memory representation, use different calling conventions or need a special treatment by the garbage collector. It is thus necessary to keep track of these informations at runtime in order to interpret or to compile a polymorphic function.
\paragraph{} A function is said to be \emph{polymorphic} when a single implementation of this function can be used with several different types. A polymorphic function may accept types that need to be treated differently at runtime. It could be because they have different memory representation, use different calling conventions or need to be discriminated by the garbage collector. It is thus necessary to keep track of these informations at runtime in order to interpret or to compile a polymorphic function.
% TODO: exemples
\paragraph{} Many polymorphism implementation techniques exist but only some of them have been described in research papers. We describe these techniques extensively, list their advantages and limitations, and compare all of them.
\section{Monomorphization}
\section{By hand: meta-programming}
\paragraph{Source code duplication by hand} TODO.
\paragraph{Source code generation} TODO.
\paragraph{Source code transformation} It is possible to generate source code using a preprocessor, this is described in~\cite{SY74} under the name \emph{syntax-macro extension}. Its is used~\cite{EBN02} in the C programming language through it's preprocessor~\cite{SW87}. The technique is described in~\cite{Reb17}. For instance, given the \commandbox{list.c} file:
\begin{tcolorbox}[breakable]
\input{list.c.tex}
\end{tcolorbox}
Running \commandbox*{cpp -P list.c} will give:
\begin{tcolorbox}[breakable]
\input{list.preprocessed.c.tex}
\end{tcolorbox}
In practice one would put the generic code in its own file. Then, defining \commandbox{TYPE} and \commandbox{TYPED(X)} before including the file is enough to get a specialised version.
\paragraph{String mixins} See D's \emph{String mixins}~\cite{Fou22}.
For instance, givent the \commandbox{list.d} file:
\begin{tcolorbox}[breakable]
\input{list.d.tex}
\end{tcolorbox}
Running \commandbox*{gdc -c list.d -fsave-mixins=/dev/stdout} will give:
\begin{tcolorbox}[breakable]
\input{list_int.d.tex}
\end{tcolorbox}
\paragraph{Token stream transformation} See Rust's \emph{procedural macros}~\cite{Dev22}.
\subsection{General description}
\paragraph{AST transformation} See OCaml's PPXs~\cite{Con22ppx}.
\paragraph{} For more metaprogramming techniques, see~\cite{LS19}.
\section{Monomorphization}
Given a polymorphic function, it is (sometimes) possible to \emph{statically} collect all the types combinations it is going to be used with. The \emph{monomorphization} technique consists in producing a different \emph{specialised} function for each combination. This results in having only \emph{monomorphic} functions, hence the name monomorphization.
@ -14,22 +52,96 @@ To build the set of types combinations for a given function, we iterate on the p
Once the set is computed, the original polymorphic function is removed. All the monomorphic functions are generated and added to the program. Finally, each call site is updated to use the right function.
\subsection{In the wild}
Monomorphization is used by Rust's generics~\cite{Con18}, C++'s templates~\cite{Str88}, Ada's generic packages and subprogram~\cite{ND79}\cite{Bar80}, Coq's extraction~\cite{TAG18}, Why3~\cite{BP11}
Monomorphization can be performed at different stages.
Monomorphization may seem similar to the various techniques described in the previous section. The difference lies in the fact that monomorphization is dedicated to handle polymorphism, whereas metaprogramming only allows polymorphism incidentally. Even if C has macros, no one would say that C is a polymorphic language. In the same vein, even if C++, D and Rust respectively have macros, String mixins and procedural macros; they also have a templates/generics system dedicated to polymorphism. The term monomorphization should be used to talk about the \emph{prefered form} of polymorphism.
\paragraph{Source code} It is possible to generate source code using a preprocessor, this is described in~\cite{SY74} under the name \emph{syntax-macro extension}. Its is used~\cite{EBN02} in the C programming language through it's preprocessor~\cite{SW87}.
\subsection{Advantages}
\inputminted[bgcolor=darkBackground]{c}{list.c}
\paragraph{Code specialisation} The code produced by monomorphization is usually very efficient. Indeed, as the types are known precisely, it is possible to generate machine code fully specialised for this type. This includes the usage of dedicated assembly instructions or calling conventions. Moreover, there's no need for any kind of runtime support as there's no need to act differently depending on the type.
%\begin{minted}[bgcolor=lightBackground]{md}
%The file can be downloaded at url `https://archive.softwareheritage.org/api/1/content/sha1_git:80131a360f0ae3d4d643f9e222591db8d4aa744c/raw/`.
%\end{minted}
\paragraph{Memory usage} Heap memory usage is optimal as we only store the values we need and no runtime metadata.
Monomorphization is used by Rust's generics~\cite{Con18}, C++'s templates~\cite{Str88}, Ada's generic packages and subprogram~\cite{ND79}\cite{Bar80}, Coq's extraction~\cite{TAG18}, Why3~\cite{BP11}
TODO: easy to compile ?
\subsection{Disadvantages}
\paragraph{Compilation cost} The compilation cost is usually quite high as the number of specialised functions per polymorphic function can be high. This leads to an increase in compilation time and memory use.
\paragraph{Binary size} For the same reason, the compiled binary can be quite huge. Each source polymorphic function potentially leading to a lot of assembly monomorphic functions.
\paragraph{Dynamic languages} Monomorphization doesn't work for dynamic languages. TODO: explain a little bit more, with an example.
\paragraph{Modularity} Monomorphization is not modular as it requires either access to the full source code, either to keep a representation of polymorphic code until linking in order to support separate compilation. TODO: explain more, with an example
\subsubsection{Polymorphic recursion}
Monomorphization is impossible in presence of polymorphic recursion, that is, a recursive function calling itself with a potentially different type each time.
It is quite easy to show with non-uniform recursive types, as they permit to write functions whose type can grow indefinitely depending on their input.
For instance, this implementation of \emph{Revisited Binary Random-Access Lists}~\cite{Oka99} in Rust:
\begin{tcolorbox}[breakable]
\input{ral.rs.tex}
\end{tcolorbox}
The Rust compiler loops indefinitely on this file as it tries to generate an infinite number of specialised versions of the \texttt{len} function. Note that without the \texttt{main} function, the compiler succeeds. That's because monomorphization can only happen at linking. Without a main function, the \texttt{len} function can't be specialised as its call sites are still partly unknown.
\subsection{Optimisations}
\paragraph{Avoid useless specialisation} When a type parameter is not used by a function, it not necessary to specialise the function for this parameter. This optimisation is performed by the Rust compiler. It's not very common for a type parameter not to be used (i.e. not to appear in arguments or result).
\paragraph{Polymorphization} When functions have closures, closures inherit type parameters from the function they belong to. In this case, it is much more common that they end up unused. The optimisation that prevent closures to be specialised for unused type parameters is called \emph{polymorphization}. The initial implementation for the Rust compiler is described in~\cite{Wo20}.
\section{Boxing}
The \emph{boxing} technique uses an \emph{uniform} representation of values: pointers. \emph{Scalar} values (integers, booleans, characters\ldots) are stored in a heap-allocated \emph{block} (sometimes called a \emph{box}) and represented by a pointer to this block. Blocks usually contain metadata describing their size and what kind of data they're made of. Values that already were pointers (arrays, lists\ldots) are still represented by a pointer, but instead of pointing directly to their data, they're pointing to a block.
TODO: figure explaining the above paragraph
All values being pointers, polymorphic function can deal with any type parameter in an unique way. At runtime, it'll be necessary to perform some operations to box and unbox values when needed. When it is required to discriminate between pointers and scalar (e.g. by the garbage collector), the information is found in the block's metadata.
TODO: figure explaining box metadata ?
It is used by the CPython implementation of Python, where blocks are named \texttt{PyObject}~\cite{pyobject}.
Considering the following code:
\begin{tcolorbox}[breakable]
\input{layout.py.tex}
\end{tcolorbox}
The memory layout would be the following:
\includegraphics[width=15em]{figure_python_layout.mps}
TODO: say that Python integers are of arbitrary size (size is stored in the block metadata ?)
TODO: say that it also wastes a lot of space (give size of a small int in Python)
TODO: say that small integers are preallocated in Python that's why x and array2\_2 are pointing to the same heap value
It is used in Java~\cite{Bra+98}. TODO: link ; TODO: explain difference with python (Java has some unboxed scalar oustide of generics)
\subsection{Advantages}
\paragraph{Ease of implementation} Boxing is one of the easiest technique to implement, it only requires to insert some code that will box, unbox and read blocks metadata at runtime.
\paragraph{Compilation cost} The compilation cost of boxing is very low. Indeed, each polymorphic function is compiled only once.
\paragraph{Binary size} The binary size of code produced by boxing is also very low, as each polymorphic function is compiled into a single assembly blob.
\paragraph{Interpreted languages} As shown by Java and Python, boxing is compatible with compiled and interpreted languages
\paragraph{Modularity} Boxing is modular. Indeed, each function can be compiled without knowing all its call site. Therefore, separate compilation is possible with boxing without any difficulty.
\paragraph{Polymorphic recursion} Boxing is compatible with polymorphic recursion. If a function calls itself with an unbound number of types, they'll all have te same representation and can therefore be handled by the same assembly code.
\subsection{Disadvantages}
\paragraph{Execution speed} TODO: It's very slow : initialization cost, indirect acces, locality, memory cost and thus GC
\paragraph{Memory usage} TODO: a lot of waste (TODO: give size of a small int in Python)
\section{Pointer-tagging}
\section{Tagged union}

88
src/bib.bib

@ -42,6 +42,24 @@
year={1988}
}
@article{Bra+98,
title={Making the future safe for the past: Adding genericity to the Java programming language},
author={Bracha, Gilad and Odersky, Martin and Stoutamire, David and Wadler, Philip},
journal={Acm sigplan notices},
volume={33},
number={10},
pages={183--200},
year={1998},
publisher={ACM New York, NY, USA}
}
@book{Oka99,
title = {Purely functional data structures},
author = {Okasaki, Chris},
year = {1999},
publisher = {Cambridge University Press}
}
@article{KS01,
doi = {10.1145/381694.378797},
url = {https://doi.org/10.1145/381694.378797},
@ -74,12 +92,19 @@
year = {2011}
}
@misc{Reb17,
title = "SamR's Assorted Musings and Rants: Using macros for generic structures in C",
author = {Rebelsky, Samuel A.},
url = {https://rebelsky.cs.grinnell.edu/musings/cnix-macros-generics},
year = 2017
}
@misc{Con18,
title = "Guide to Rustc Development - Monomorphization",
author = {The Guide To Rustc Development Contributors},
howpublished = "\url{https://rustc-dev-guide.rust-lang.org/backend/monomorph.html}",
year = 2018,
note = "Accessed: 2022-12-23"
title = "Guide to Rustc Development - Monomorphization",
author = {The Guide To Rustc Development Contributors},
url = {https://rustc-dev-guide.rust-lang.org/backend/monomorph.html},
year = 2018,
note = "Accessed: 2022-12-23"
}
@article{TAG18,
@ -91,3 +116,56 @@
year={2018},
publisher={Information Processing Society of Japan}
}
@article{LS19,
title={A survey of metaprogramming languages},
author={Lilis, Yannis and Savidis, Anthony},
journal={ACM Computing Surveys (CSUR)},
volume={52},
number={6},
pages={1--39},
year={2019},
publisher={ACM New York, NY, USA}
}
@mastersthesis{Wo20,
author = "Wood, David",
title = "Polymorphisation: Improving Rust compilation times through intelligent monomorphisation",
school = "University of Glasgow",
year = 2020,
month = apr,
url = {https://davidtw.co/media/masters_dissertation.pdf}
}
@misc{Dev22,
title = "The Rust Language Reference - Procedural Macros",
author = {The Rust Project Developers},
url = {https://doc.rust-lang.org/reference/procedural-macros.html},
year = 2022
}
@misc{Fou22,
title = "String Mixins",
author = {D Language Foundation},
url = {https://dlang.org/articles/mixin.html},
year = 2022
}
@misc{Con22ppx,
title = "OCaml - Metaprogramming - PPXs",
author = {ocaml.org Contributors},
url = {https://ocaml.org/docs/metaprogramming#ppxs},
year = 2022
}
@codefragment{pyobject,
title = {CPython},
date = {2022},
url = {https://github.com/python/cpython/blob/main/Include/object.h},
subtitle = {PyObject header file},
swhid = {swh:1:cnt:3774f126730005469a7c3dc48bca0fd9a898b33f;
origin=https://github.com/python/cpython;
visit=swh:1:snp:413f8b76b7dd0aafb25c1451a4b43b824784cc4f;
anchor=swh:1:rev:84bc6a4f25fcf467813ee12b74118f7b1b54e285;
path=/Include/object.h}
}

98
src/dune

@ -1,6 +1,18 @@
(rule
(targets main.pdf)
(deps main.bbl article.tex main.tex packages.tex)
(deps
article.tex
figure_python_layout.mps
layout.py.tex
list.c.tex
list.preprocessed.c.tex
list.d.tex
list_int.d.tex
main.bbl
main.tex
packages.tex
ral.rs.tex
styledef.tex)
(action
(pipe-outputs
(run texfot xelatex -halt-on-error -shell-escape main.tex)
@ -24,7 +36,18 @@
(rule
(targets main.bcf)
(deps article.tex main.tex packages.tex)
(deps
article.tex
figure_python_layout.mps
layout.py.tex
list.c.tex
list.preprocessed.c.tex
list.d.tex
list_int.d.tex
main.tex
packages.tex
ral.rs.tex
styledef.tex)
(action
(pipe-outputs
(run texfot xelatex -halt-on-error -shell-escape main.tex)
@ -40,7 +63,74 @@
(run sed "/Package biblatex Warning:/d")
(run sed "/Output written/d"))))
(rule
(targets list.c.tex)
(deps styledef.tex list.c)
(action
(run pygmentize -O envname=BVerbatim list.c -o %{targets})))
(rule
(targets styledef.tex)
(deps get_style_def.py)
(action
(with-stdout-to
%{targets}
(run python get_style_def.py))))
(rule
(targets list.preprocessed.c.tex)
(deps styledef.tex list.preprocessed.c)
(action
(run pygmentize -O envname=BVerbatim list.preprocessed.c -o %{targets})))
(rule
(targets list.preprocessed.c)
(deps list.c)
(action
(with-stdout-to
%{targets}
(run cpp -P list.c))))
(rule
(targets list_int.d.tex)
(deps styledef.tex list_int.d)
(action
(run pygmentize -O envname=BVerbatim list_int.d -o %{targets})))
(rule
(targets list_int.d)
(deps list.d)
(action
(run gdc -c %{deps} -fsave-mixins=list_int.d)))
(rule
(targets list.d.tex)
(deps styledef.tex list.d)
(action
(run pygmentize -O envname=BVerbatim list.d -o %{targets})))
(rule
(targets ral.rs.tex)
(deps styledef.tex ral.rs)
(action
(run pygmentize -O envname=BVerbatim ral.rs -o %{targets})))
(mdx
(deps
(file list.c))
(deps list.c list.d)
(files CODE.md))
(rule
(targets layout.py.tex)
(deps styledef.tex layout.py)
(action
(run pygmentize -O envname=BVerbatim layout.py -o %{targets})))
(library
(name figures)
(libraries mlpost))
(rule
(targets figure_python_layout.mps)
(deps figures.ml)
(action
(run mlpost %{deps})))

71
src/figures.ml

@ -0,0 +1,71 @@
open Mlpost
open Box
(* a named box intended to be used as a pointer which implies empty content *)
let named_ptr name = box ~name (tex " ")
(* a named box intended to be used as a block metadata which implies filled with black *)
let named_meta name = box ~name ~fill:Color.lightred (tex " ")
(* a block of pointers, all elements are named, the first one is a metadata box all others are ptr boxes *)
let ptr_block name names =
hblock @@ (named_meta name :: List.map named_ptr names)
(* a block of scalars, only the metadata is named, all other have content (the scalar value) *)
let scalar_block name values = hblock @@ (named_meta name :: List.map tex values)
(* a stack ptr entry, s is the variable name and the pointer box will also be named after it *)
let stack_ptr s = hbox [ tex (Format.sprintf "\\texttt{%s}:" s); named_ptr s ]
(* a stack made of stack entries *)
let stack l = vbox ~padding:(Num.em 2.) [ tex "stack:"; vbox l ]
let figure_python_layout =
let stack =
stack
[ stack_ptr "array1"
; stack_ptr "array2"
; stack_ptr "pair"
; stack_ptr "x"
]
in
let heap =
vbox ~padding:(Num.em 2.)
[ tex "heap:"
; hbox ~padding:(Num.em 1.)
[ scalar_block "1_meta" [ "1" ]
; scalar_block "2_meta" [ "2" ]
; scalar_block "3_meta" [ "3" ]
]
; ptr_block "array1_meta" [ "array1_1"; "array1_2"; "array1_3" ]
; ptr_block "pair_meta" [ "pair_1"; "pair_2" ]
; ptr_block "array2_meta" [ "array2_1"; "array2_2"; "array2_3" ]
; hbox ~padding:(Num.em 1.)
[ scalar_block "42_meta" [ "42" ]
; scalar_block "99_meta" [ "99" ]
; scalar_block "666_meta" [ "666" ]
]
]
in
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in
Command.seq
[ draw figure
; ptr "array1" "array1_meta"
; ptr "array1_1" "1_meta"
; ptr "array1_2" "2_meta"
; ptr "array1_3" "3_meta"
; ptr "array2" "array2_meta"
; ptr "array2_1" "42_meta"
; ptr "array2_2" "99_meta"
; ptr "array2_3" "666_meta"
; ptr "pair" "pair_meta"
; ptr "pair_1" "array1_meta"
; ptr "pair_2" "array2_meta"
; ptr "x" "42_meta"
]
let () =
Array.iter
(fun (name, figure) -> Metapost.emit name (Picture.scale (Num.em 1.) figure))
[| ("figure_python_layout", figure_python_layout) |]

5
src/get_style_def.py

@ -0,0 +1,5 @@
import pygments.formatters.latex
f = pygments.formatters.latex.LatexFormatter(style="one-dark", background_color="black")
print(f.get_style_defs())

4
src/layout.py

@ -0,0 +1,4 @@
array1 = [1, 2, 3]
array2 = [42, 99, 666]
pair = (array1, array2)
x = 42

15
src/list.c

@ -1,21 +1,14 @@
extern void exit(int);
// asking for an int version
#define TYPE int
#define TYPED(X) int_##X
// generic code
struct TYPED(list) {
TYPE head;
struct TYPED(list) *tail;
struct TYPED(list) * tail;
};
TYPE hd(struct TYPED(list) *l) {
if (l) {
return l->head;
}
exit(42);
TYPE hd(struct TYPED(list) * l) {
if (l) { return l->head; }
_Exit(42);
}

13
src/list.d

@ -0,0 +1,13 @@
template GenList(string Type) {
const char[] GenList =
"struct List_" ~ Type ~ " {\n" ~
" " ~ Type ~ " head;\n" ~
" " ~ "List_" ~ Type ~ "* tail;\n" ~
"}\n" ~
Type ~ " hd(List_" ~ Type ~ "* l) {\n" ~
" if (l) { return l.head; }\n" ~
" assert(0);\n" ~
"}";
}
mixin(GenList!("int"));

37
src/packages.tex

@ -9,13 +9,20 @@
\usepackage{authblk} % author affiliation handling
\renewcommand\Affilfont{\itshape\small}
\usepackage[
cache=false,
draft=false
]{minted} % source code
\setminted{autogobble=true,breakanywhere=true,breakautoindent=true,breaklines=true,frame=none,fontseries=m,linenos,stepnumber=1}
\usemintedstyle{onedark}
\usemintedstyle{paraiso-dark}
\usepackage{fancyvrb} % source code
\input{styledef.tex} % source code
\usepackage[most]{tcolorbox}
\definecolor{darkBackground}{HTML}{282c34} % source code background
\definecolor{lightBackground}{HTML}{D7D3CB} % source code background
\tcbset{colback=darkBackground}
\DeclareTotalTCBox{\commandbox}{ s v }
{verbatim,colupper=white,colback=black!75!white,colframe=black}
{\IfBooleanT{#1}{\textcolor{red}{\ttfamily\bfseries \$ }}%
\lstinline[language=sh,keywordstyle=\color{blue!35!white}\bfseries]^#2^}
\usepackage[
autolang=other,
@ -24,15 +31,21 @@
backrefstyle=none, % afficher toutes les utilisations de la référence
bibstyle=alphabetic, % style pour les clés des références dans la bibliographie : [initialesAnnée]
citestyle=alphabetic, % style pour les clés des références dans le texte : [initialesAnnée]
sorting=none, % bibliographie triée par ordre d'utilisation des références
]{biblatex} % support des bibliographies
%datamodel=software, % swh
sorting=ynt, % bibliographie triée par année, nom, titre
]{biblatex} % support des bibliographies
\usepackage{software-biblatex}
\ExecuteBibliographyOptions{
swhid=true,
shortswhid=true,
swlabels=true,
vcs=true,
license=false
}
\setmainfont{Linux Libertine O}
\setsansfont{Linux Biolinum O}
%\setsansfont{TeX Gyre Heros}
\setmonofont[Scale=MatchLowercase]{RobotoMono Nerd Font}
\definecolor{darkBackground}{HTML}{282c34} % source code background
\definecolor{lightBackground}{HTML}{D7D3CB} % source code background
\hypersetup{colorlinks=true, pdfstartview=FitH}

19
src/ral.rs

@ -0,0 +1,19 @@
pub enum Enum<T> {
Nil,
Zero(Box<Enum<(T, T)>>),
One { head : T, tail : Box<Enum<(T, T)>> },
}
impl<T> Enum<T> {
pub fn len(&self) -> usize {
match self {
Self::Nil => 0,
Self::Zero(sub) => 2 * sub.len(),
Self::One { tail, .. } => 1 + 2 * tail.len()
}
}
}
fn main() {
let val: Enum<usize> =
Enum::One { head : 42, tail: Box::new(Enum::Nil)};
println!("len: {}", val.len());
}
Loading…
Cancel
Save