Scheme+ is an extension of the syntax of the Scheme language.
Scheme+ is to Scheme what a concept-car is to
automobile.Scheme+ is a concept-language.It is ideally what
should be a modern Scheme.
Scheme+ makes it easy the assignment of Scheme objects in
infix (works also in prefix) notation with a few
new operators ← (or
<-), [ ],⥆ (or <+) .
The idea of Scheme+ first come to my mind when comparing the
assignation syntax used in Clojure with Scheme and Lisp, and later
the easyness of creating and assigning variables in Python
completely convince me that the Scheme system have to be enhanced.
The idea of Scheme+ is also came from this : "Why is it
so boring to define variables in Scheme with the traditionnal set of
LET,LET*,LETREC,LET-VALUES special forms?" and "Is it
possible to use a single mechanism for assignment in Scheme?"
It comes also from the ascertainment that "A computer language is
created by ONE man, later, a community only bring a library to the
language without self-questioning any more on the fundations of
language itself."
Scheme+ brings syntax to classic Scheme language like
those:
{x <- y} infix assignment of the
value of y to the variable x.
The same thing with a new symbol
← : (unicode 2190 in hexadecimal that can be enter under Linux
with Ctrl-Shift u 2190 Enter or Space bar)
{x ← y}
With operator precedence: {xp <-
{x - v * t} / (sqrt {1 - v ** 2 / c ** 2})}
defining new functions with def instead of the classic define we
can now use return to escape immediately from the current level of recursive call and return-rec to escape from the full stack of recursive calls:
(return)
or returning the value v:
(return v)
The <+ operator works also for
defining multiple values :
{(a b c) <+ (values 7 8 9)}
7
8
9
(list a b c)
'(7 8 9)
{(x y z) <+ (u v w) <+ (a b
c) <+ (values 2 4 5)}
2
4
5
(list x y z u v w a b c)
'(2 4 5 2 4 5 2 4 5)
We can also assign multiple values on
the fly:
(declare x y z)
{(x y z) <v (values 2 4 5)}
2
4
5
(list x y z)
'(2 4 5)
(declare u v w)
{(x y z) <v (u v w) <v (values 2 4 5)}
2
4
5
(list x y z u v w)
'(2 4 5 2 4 5)
Here is an example of the previous features:
(declareL-initt-initlsdynacpt){L-init<-'(13416172445641972562753235407238899151040104110931099111112841344152020272500273430003267361042855027)}{t-init<-35267}{ls<-(lengthL-init)}{dyna<-(make-array0{ls+1}{t-init+1})}(define(one-twob)(ifb12)){cpt<-0}(def(subset-sum-dynamicLt)(declarelsdyncRs);; declare multiple variables{ls<-(lengthL)}{dyn<-dyna[lst]};; dyna is a toplevel defined array;; dyna[ls t] means : 0: unknown solution, 1: solution found, 2: no solution(if{dyn<>0};; IF or WHEN : it is the same thing here (only one statement)(return(one?dyn)))(when(null?L){dyna[lst]<-2}(return#f)){c<-(firstL)}(when{c=t};; c is the solution{dyna[lst]<-1}(return#t)){R<-(restL)};; continue searching a solution in the rest(if{c>t};; c is to big to be a solution{s<-(subset-sum-dynamicRt)};; c is part of the solution or c is not part of solution{s<-(subset-sum-dynamicR{t-c})or(subset-sum-dynamicRt)}){dyna[lst]<-(one-twos)}s);; return boolean value
(subset-sum-dynamic L-init t-init)
#t
Operator and function overloading:
A possibility of defining overloaded functions or operators (just add
'operator) is given with this syntax:
Note that when a function that overload an operator has more than 2 args (f a1 a2 a3 ...) and only (f a1 a2) is defined
we do: (f a1 (f a2 a3 ...)) for operators.
A complete set of new procedures and macros:
allow overloading of both
functions and operators. Those macros call procedures written
recursively or imperatively with hast tables depending of scheme
implementation because all predicate must be test to find the matching
procedure as Scheme is not a typed language.
Warnings about code highlighting tag due to bugs in Github Markdown
system:
-if you read this page on github.com the code examples display
encapsuled between tags 'highlight scheme' and 'endhighlight'
composed also with {} and % characters.
-if you read this page on github.io the code examples display
starting with 3 backquotes char , the tag 'scheme' and ending again
with 3 backquotes char. The curly brackets {} display in a
rectangular with red background because the Github Jekill rouge
theme (unfortunately the ony one available) does not understand the
infix notation of Scheme.This is,of course, not what i expected but i
can not find any issue to this problem.
Copyright (C) 1995-2021 Free
Software Foundation, Inc.
scheme@(guile-user)>
scheme@(guile-user)>
(declare L)
scheme@(guile-user)> {L
<- '(1 2 3 4)}
$1 = (1 2 3 4)
scheme@(guile-user)> L
$2 = (1 2 3 4)
scheme@(guile-user)> {L
<- (list 1 2 3 4 5)}
$3 = (1 2 3 4 5)
Hash Tables support :
(use-modules (srfi srfi-69)) ;; support for SRFI 69 Basic hash tables
{my-hash-tbl <+ (make-hash-table)} ;; add an object in the current environment, here a hash table
(hash-table? my-hash-tbl)
#t
{my-hash-tbl["three"] <- 3}
3
{my-hash-tbl["three"]}
3
Note that infix programs needs to include the #!curly-infix statement if you have not configured your guile init file for curly infix.
Programs now needs to be parsed due to the use of optimization
schemes, for parsing do:
The growable vector module class in the file
growable-vector.scm.
The enhanced set of LET special forms in the
file let.scm.
Many of the examples of this web page are in
the source file SssDyna.scm.
The .guile configuration file i use with Scheme+.
3.Requirements:
Scheme+ needs a Scheme interpreter and will be adapted and released for
many Scheme (Guile,Racket,...), download Scheme Guile:
This version needs Guile Scheme version 3. It has been developed with
Guile 3.0.7 on MacOS
and Guile 3.0.1 under Linux.
Guile offers infix notation that can be activated this way: for curly
infix notation put in your .guile file : (read-enable
'curly-infix)
Also you need to activate in Guile the OOP option (Object Oriented
Programming)
Also Guile can be more easy to use with history on command line, completion,
as example here is my .guile init file:
;; Guile config file;; history(use-modules(ice-9readline)(ice-9history)(srfisrfi-43);; vector;; guile object oriented programming system(oopgoops)(oopgoopsdescribe))(activate-readline);;(disable-value-history!);; curly infix as in srfi-105(read-enable'curly-infix);; set current path in load path(set! %load-path(reverse (cons "."(reverse %load-path))));; other solution is to put this in shell:;; export GUILE_LOAD_PATH="...:."
This .guile file is included in the Scheme+ repository.
The core language of Scheme and Lisp are based on syntaxic form that date back from
'50 for Lisp and '70 for Scheme. Syntactic forms such as the set of
LET,LET*,LETREC,... have since long ago been replaced in many other
languages (C/C++,Java,Fortran,Pascal,Javascript,BASIC (the LET keyword can
be ommited in Applesoft Basic),by simple assignment operator that frees
the syntax and allow saving indentation space, number of parenthesis,
readability of code.
The main idea of this project is to improve Scheme and Lisp like
languages with syntaxic features,such as easy assignment for many object
types (numbers,strings,vectors,arrays,etc),and also allowing an immediate
'return' mechanism to escape from procedure when result is known and
others features that exist in others languages
(Python,Java,C/C++,Pascal,BASIC,Javascript). Some new features can be and
are better used with infix notations (SRFI 105 known as "Curly Infix"),so for some
syntactic expressions infix will be promoted (but not mandatory).
A few new feature (see below) allow a great change in syntax and
readability of Scheme programs. Less parenthesis are used,less indentation
and it allows an enhanced programming style that modernize Scheme but also
keep it 100% compatible with the original language.
Also vectors and arrays in Scheme are painfully accessed and modified by
vector-ref and vector-set! , Scheme+ use a simplier syntax again with the
<- operator and the [] syntax.
This intuitive notation works also with Hash Tables.
Scheme+ will remove the need for the classic LET set of special form, no
more need of LET,LET*,LETREC,LET-VALUES,... and will use
an unique infix (or not) assignment operator : <-. (also LET are
enhanced - the project starts historically by improving and simplifying LET, i
simplified it so much that i remove it now! - in other versions such as
let<-arrow requiring less brackets, even if their use is useless and no
more promoted, see extra features part)
7. Features:
The list of new features is subject to change and will grow by time, this
version allows:
use of infix SRFI 105 "Curly Infix" for some syntax forms
Assignment operator : <- (can be used in infix syntax and
from left to right and right to left)
Square Bracket operator [] working with Scheme Vectors,
Arrays,Multidimentional Arrays,Dynamic Arrays (my growable vector
class),Hash Tables...
combination of Assignment operator <- with [] operator for
Vectors,Arrays,....
RETURN : return keyword used in any procedure to return from
procedure and return a value.
declaration of variables
declaration and assignment of variables with an infix operator.
conditionals and execution of code in a new form : condx
extra feature: new set of LET special forms,even if their use is
completely discouraged in favor of assignment operator combined with
declarative form (see declare).
This example is written in Scheme with and
without infix notation just to allow the reader to be familiar with "curly
infix" notation which is not part of Scheme+ but used by it:
And here is a definition using "Curly Infix"
SRFI 105:
(define(fibn)(if{n<2}n{(fib{n-1})+(fib{n-2})}))
note that the last expression of fib: {(fib {n - 1}) + (fib {n - 2})}
could also be expressed in curly infix Scheme like that : {fib({n -
1}) + fib({n - 2})} or even like that: {fib{n - 1} + fib{n - 2}}
but i will not use them, preferring to use infix only where
mathematical calculus are coded and for comparaison tests in conditionals.
Fibonacci is time consuming,even fib(47) can takes minutes to compute. We
will write a faster dynamic version that memorize the results computed
more than one time.
In the example above we can notice that the array access and modification
is not easy to read and in the else block i have to use a let
special form to create a local variable to return the value computed and
already stored in array,even if i have not used a local variable i then
must have to access the result in array to return it...
Scheme+ allow to write code more readable and simpler than normal Scheme.
Prior to use Scheme+ for the implementation of Scheme named
Guile, the code must be loaded,this is done by inserting the
statement
(use-modules (Scheme+))
at the beginning of the Scheme
source file.
Below is the version of the above code written in Scheme+ :
The reader can notice the introduction of one new assignment operator <-
and also <+, the latter being simply an infix define of
Scheme. The important point of the new assignment operator <-
of Scheme+ is that it will work like the classic set! of
Scheme on variables but also will work on more complex object such as
element of vectors,multidimensional arrays (as defined in
SRFIs),growable vectors (my class),... and much more in the next
versions of Scheme+. (we will see another more complex example with
multidimentional array later)
So {x <- 7} simply assign 7 to the variable x but {m[3]
<- 7} will store 7 in the array m at the position
indexed by 3. Access an element of array is also simpler in Scheme+ than
in Scheme: {m[3]}. And this syntax is 100% compatible with Scheme,
you can mix both the syntaxes if you want. This syntax is also more
natural and readable and much like the mathematical notation, it is also a
syntax used for arrays in other languages such as
C/C++,Python,Java,Pascal,Javascript...
Also you will notice that the main computation in the else
block is now shorter and it is partly due to the fact that the assignment
operator <- return not NIL but the affected value
making it available for other calculus or as a final result value.
Here is now the same solution in a declarative form, in the part
called "History of project" i explain why there exist two solutions.
Instead of declare and assign the variables with the define
nested in the macro <+ we also can declare them and
assign the variables later with the universal <- operator:
Square bracket operator [] is used for vectors,arrays,growable
vectors,hash tables,etc.
example: {T[k]} return value of vector or array T indexed by k.
Assignment operator <- can be used only on existing single
variables or vector,arrays,etc . Note that vector and arrays must be
defined the usual way they are in Scheme. The operator <- works also
with multidimensional arrays.
examples :
{x <- 7}
{x <- y}
{m[3] <- 7}
{T[k] <- x}
{T[k] <- T[k + 1]}
{T[m n] <- T[m {n +
1}]}
{my-hash-tbl["three"] <- 3}
Definition and assignment of variables is made with the <+
operator but can also be done with the classic Scheme define.
example: {size <+ 1000}
Declaration of variable can also be used to declare one or many
variables. (for explanation why there exist still <+ and declare
and not only <- read the part history of project)
example: (declare x y z t)
How to load a Scheme+ program:
Scheme+ programs are loaded the usual way,example:
(load "start-λογικι-guile+.scm")
(infix-symb-min-dnf '{ {(not a) and (not b) and (not c) and (not d)} or {(not a) and (not b) and (not c) and d} or {(not a) and (not b) and c and (not d)} or {(not a) and b and (not c) and d} or {(not a) and b and c and (not d)} or {(not a) and b and c and d} or {a and (not b) and (not c) and (not d)} or {a and (not b) and (not c) and d} or {a and (not b) and c and (not d)} or {c and (not d)} } )
disj-norm-form = (or (and c (not d)) (and (not a) (not b) (not c) (not d)) (and (not a) (not b) (not c) d) (and (not a) b (not c) d) (and (not a) b c d) (and a (not b) (not c) (not d)) (and a (not b) (not c) d))
((!b ^ !c) v (c ^ !d) v (!a ^ b ^ d))
We can use a convention to name the Scheme+ programs and function with a
+ at end, keeping the .scm extension unchanged for compatibility.
10.Advanced examples:
Here is another example, from the Subset Sum Problem that show the use of <+
and <- (due to the impossibility to have easily a single
operator :-( ) :
(use-modules (Scheme+))
{L-init<+'(13416172445641972562753235407238899151040104110931099111112841344152020272500273430003267361042855027)}{t-init<+35267}{ls<+(lengthL-init)}{dyna<+(make-array0{ls+1}{t-init+1})}{cpt<+0};; define cpt to 0(define(subset-sum-guileLt){ls<+(lengthL)}{dyn<+dyna[lst]}{cpt<-{cpt+1}};; cpt has been already defined at toplevel;; dyna[ls t] means 0: unknown solution, 1: solution found, 2: no solution(condx[{dyn<>0}(one?dyn)][(null?L){dyna[lst]<-2}#f];; return #f[exec{c<+(firstL)}];; c is the solution[{c=t}{dyna[lst]<-1}#t];; return #t[exec{R<+(restL)}];; continue searching a solution in the rest[{c>t}{s<+(subset-sum-guileRt)}{dyna[lst]<-(one-twos)}s];; return boolean value;; else : c < t at this point;; c is part of a solution OR not part of a solution[else{s<+{(subset-sum-guileR{t-c})or(subset-sum-guileRt)}}{dyna[lst]<-(one-twos)}s]));; return boolean value
In classic Scheme the code would be like that
which is longer than in Scheme+:
(definecpt0)(define(ssigma-protoLt)(set!cpt{cpt+1})(definels(lengthL))(definedyn(array-refdynalst));; dyna[ls][t] means 0: unknown solution, 1: solution found, 2: no solution(cond[(not(zero?dyn))(one?dyn)][(null?L)(array-set!dyna2lst)#f];; return #f[else(let[(c(firstL))](if{c=t};; c is the solution(begin(array-set!dyna1lst)#t);; return #t;; else(let[(R(restL))](if{c>t};; continue searching a solution in the rest(let[(s(ssigma-protoRt))](array-set!dyna(one-twos)lst)s);; return s;; else;; c < t at this point;; c is part of the solution or his approximation;; or c is not part of solution(let[(s{(ssigma-protoR{t-c})or(ssigma-protoRt)})](array-set!dyna(one-twos)lst)s)))))]))
If you want to use a single assignment operator
<- it is possible using a declarative programming style with the
declare macro:
(use-modules (Scheme+))
(declareL-initt-initlsdynacpt){L-init<-'(13416172445641972562753235407238899151040104110931099111112841344152020272500273430003267361042855027)}{t-init<-35267}{ls<-(lengthL-init)}{dyna<-(make-array0{ls+1}{t-init+1})}(define(one-twob)(ifb12)){cpt<-0}(define(subset-sum-guile-decLt)(declarelsdyncRs){ls<-(lengthL)}{dyn<-dyna[lst]}{cpt<-{cpt+1}};; cpt has been already defined at toplevel;; dyna[ls t] means 0: unknown solution, 1: solution found, 2: no solution(condx[{dyn<>0}(one?dyn)][(null?L){dyna[lst]<-2}#f];; return #f[exec{c<-(firstL)}];; c is the solution[{c=t}{dyna[lst]<-1}#t];; return #t[exec{R<-(restL)}];; continue searching a solution in the rest[{c>t}{s<-(subset-sum-guile-decRt)}{dyna[lst]<-(one-twos)}s];; return boolean value;; else : c < t at this point;; c is part of a solution OR not part of a solution[else{s<-(subset-sum-guile-decR{t-c})or(subset-sum-guile-decRt)}{dyna[lst]<-(one-twos)}s]));; return boolean value
It is also possible to use return
keyword in function definition by def macro and have again
another programming style with if then else that looks like
traditionals language such as Python,Javascript,C/C++,etc... :
This example mix many Scheme+ Style and
illustrate the use of return in a Python/C++ style:
(use-modules (Scheme+))
(def(subset-sum-dynaLt)(declarelsdyn);; declare multiple variables{ls<-(lengthL)}{dyn<-dyna[lst]};; dyna[ls t] means : 0: unknown solution, 1: solution found, 2: no solution(if{dyn<>0};; IF or WHEN : it is the same thing here (only one statement)(return(one?dyn)))(when(null?L){dyna[lst]<-2}(return#f)){c<+(firstL)}(when{c=t};; c is the solution{dyna[lst]<-1}(return#t)){R<+(restL)};; continue searching a solution in the rest(declares)(if{c>t};; c is to big to be a solution{s<-(subset-sum-dynaRt)};; c is part of the solution or c is not part of solution{s<-(subset-sum-dynaR{t-c})or(subset-sum-dynaRt)}){dyna[lst]<-(one-twos)}s);; return boolean value
Here is another overloading example:
(use-modules (Scheme+))
; first stage overloading(define-overload-existing-operator+)(define-overload-existing-operator*)(define-overload-procedureuniform); second stage overloading(overload-existing-operator+vector-append(vector?vector?))(overload-existing-operator*multiply-flomat-vector(flomat?vector?))
(use-modules (Scheme+))
;; return a number in ]-1,1[;; the dummy parameter is needed by a flomat procedure(define(uniform-dummydummy){(random)*(if{(random2)=0}1-1)}); we randomly choose the sign of the random number; return a random number between [inf, sup](define(uniform-intervalinfsup){gap<+{sup-inf}}{inf+gap*(random)})(overload-procedureuniformuniform-dummy(number?))(overload-procedureuniformuniform-interval(number?number?))
11. History of project:
First i developped a new set of LET special forms with less bracket use
and after i decided to use another assignment scheme based on infix
operator for a little part,at some point the new assignment scheme was
became so perfect that we no more need the set of LET special forms.But i
also released the new set of LET special forms even if i consider those
useless.Unfornunately Scheme do not allow to use only a single assignment
operator because of declaration (define) of variables and set! are
different and it does not exist a define-or-set! function. So i only had
the choice to use 2 assignment operators, one acting as define (<+)
and the other as set! (<-) or a single assignment
operator <- and a declarative macro called declare
which should be interesting for typed Scheme implementations too.
12.Additional documentation:
condx is a macro that allow execution of arbitrary code between
conditionals clauses,syntax is :
condx is not a major feature of Scheme+
but it can replace a lot of 'if then elif', i dislike and still
misunderstand sometimes, 'else if' since BASIC !
defining new functions with def
instead of the classic define we can now use return to escape immediately
returning the value v:
(return v)
$ is a macro, it is a shortcut for begin.
But begin is dual in Scheme, it expands
differently in expression context and definition context.
See this for more information:
Inherent to Scheme language it as not been possible to simplify more
assignment operator in a single one case. This is due to the fact that it
can not be written a macro that do define-or-set! and that define can not
be placed any where. See discussion in Guile devel mailing list archive in September 2021
For the place of define, by chance,some Scheme implementation allow define
to be placed almost anywhere.
14.Implementation:
Mainly with Scheme macros which are not recursive (except in some
obsolete features),so expansion is fast and code also. It also allows a
great portabilty from one Scheme implementation to another one.
15.Future:
Scheme+ will be implemented for other Scheme. Racket (former DrScheme)
first,....
16.Extra features:
The growable vector class which is not specific to Scheme+ is
included in Scheme+ because it is intrinsic with <- operator of
Scheme+.
"Growable vectors" are vectors with size growing dynamically when
necessary. The documentation and examples are in the source code header.
Usage: (use-modules (growable-vector))
Not using the module will just show a warning like "possibly undefined
function growable-vector?" as it is used in assignment.scm.No problem till
you do not create a growable vector, and when you will do it you will have
loaded the growable module class before and the warning message will
vanish.This is the force of Scheme on other language:you can have an
undefined function in your source code and it can run without
problem (till the function is not called of course! which is the case in
my code if no growable vector exist in your code too)
As mentioned early the project idea was initially to enhance the set of
LET special form. The use of the LET set is no more need with the new
assignment operator but i release anyway those set of enhanced and
simplified LETs, i just give some examples as names are self-explanatory.
The way to be able to use the new set of LET special form is to load the
file let.scm which is available in the Scheme+ directory:
(load "let.scm")
Examples:
(let<-rec*[x<-1y<-(+x1)z<-(+2y)]z)4
and here is the source code of this recursive macro defined with
an accumulator:
(define-syntaxlet<-rec*(syntax-rules(<-)((_()expr...)(beginexpr...));; case empty let((_(var1<-val1)expr...)(letrec*((var1val1))expr...));; case single binding((_(var1<-val1;; multiple bindingvar2<-val2...)expr...)(%parse-letrec-bindings-and-evaluate-expressions((var1val1))(var2<-val2...)expr...))));; recursive macro with accumulator(define-syntax%parse-letrec-bindings-and-evaluate-expressions(syntax-rules(<-)((_(bindings...)(var1<-val1)expr...)(letrec*(bindings...(var1val1));; last bindingexpr...));; we evaluate expressions((_(bindings...)(var1<-val1;; multiple bindingvar2<-val2...)expr...);; store (var1 val1) binding in accumulator and continue parsing(%parse-letrec-bindings-and-evaluate-expressions(bindings...(var1val1))(var2<-val2...)expr...))))
a few others special forms simplifying the LETs (but still obsolete in my
opinion):
Github web site technology force me to convert this page in Github Markup
Language, perheaps instead of HTML should i have make it directly in GML
but i did not know it existed before doing it. I did not want to make this
documentation so long and graphically complex to set up. Well it's done! i
hope you get interest in reading at least 10% :-) . And get as
pleasure to read and use than i take making and writing it. This documentation is at end and it is quite impressive how long it
takes to document things! Even if i suppose i could have
forget things to talk about.
19. Special characters (for special people):
This is about the optional replacement symbols for some operators:
(def(Petricknon-essential-prime-implicantsvar-list);; create the conjunction of disjunction expression(declaremtconj-exprprim-impcoldisj-exprdisj-expr-sortedmt-varmissing-term)(display-nl"Entering Petrick...")(for(x1lgt-mt);; loop over minterms{mt←iepi[x0]}(when(membermtnon-expressed-minterms);; non expressed minterm{col←'()}(for(y1lgt-pi);; loop over prime implicants{prim-imp←iepi[0y]};; prime implicant;; check wether prime implicant is a non essential one?(when(memberprim-impnon-essential-prime-implicants);; is the non essential prime implicant expressing this minterms?(when(string=?{iepi[xy]}" * ")(insert-set!(minterm->varprim-imp)col))));; end for y(if(singleton-set?col){col←(carcol)};; ( V ) -> V(insert-set!'orcol));; (V1 V2 ...) -> (or V1 V2 ...)(insert-set!colconj-expr)));; end for x(if(singleton-set?conj-expr){conj-expr←(carconj-expr)};; ( conj-expr ) -> conj-expr(insert-set!'andconj-expr));; (e1 e2 ...) -> (and e1 e2 ...);; find the disjunctive form{disj-expr←(dnf-n-arity-simpconj-expr)};; sorting terms;; sort by x < 1 < 0{disj-expr-sorted←(sort-arguments-in-operation-most-little-literal-firstdisj-expr)};; get the shortest minterm(if(isOR-AND?disj-expr-sorted){mt-var←(first(argsdisj-expr-sorted))}{mt-var←disj-expr-sorted}){mt←(var->mintermmt-var)};; TODO: possible bug missing term could be an expression ? (multiple terms){missing-term←(essential-prime-implicants-list->formula(listmt)var-list)}missing-term)
(def(Quine-Mc-Cluskeydisj-norm-formvar-list)(display-nl"Entering Quine-Mc-Cluskey"){and-terms⥆(argsdisj-norm-form)};; conjunctives minterms;; variable list of expanded minterms {expanded-var-terms⥆(${debug-mode-save←debug-mode}{debug-mode←#t}(whendebug-mode(dvand-terms));; dv:display value{debug-mode←debug-mode-save}(applyappend(map(lambda(min-term)(expand-mintermvar-listmin-term))and-terms)))}{sorted-expanded-var-terms⥆(mapsort-argumentsexpanded-var-terms)};; sorted variable list of expanded minterms{binary-minterms⥆(mapvar->binarysorted-expanded-var-terms)};; minterms in binary form{sorted-binary-minterms⥆(sortbinary-mintermsminterm-binary-weight-number<?)};; sorted binary minterms{uniq-sorted-binary-minterms⥆(remove-duplicates-sortedsorted-binary-minterms)};; prevoir uniq pourquoi???? sais plus !{minterms⥆uniq-sorted-binary-minterms}{set-of-sets-of-minterms⥆(order-by-weight-mintermsuniq-sorted-binary-minterms)};; set of sets of minterms ordered by weight{unified-minterms⥆(${debug-mode-save←debug-mode}{debug-mode←#t}(whendebug-mode(display-nl"Quine-Mc-Cluskey:"))(init-hash-table-with-set-and-valueminterms-htminterms#f)(dvminterms-ht){debug-mode←debug-mode-save}(recursive-unify-minterms-set-of-setsset-of-sets-of-minterms))}{essential-prime-implicants⥆(${prime-implicants-lst←(${debug-mode←debug-mode-save}(prime-implicantsminterms-ht))}(identify-essential-prime-implicantsprime-implicants-lstminterms))};; dv : display value(dvdisj-norm-form)(dvvar-list)(dvand-terms)(dvexpanded-var-terms)(dvsorted-expanded-var-terms)(dvbinary-minterms)(dvsorted-binary-minterms)(dvuniq-sorted-binary-minterms)(dvsosset-of-sets-of-minterms)(dvunified-minterms)(dvminterms-ht)(dvprime-implicants-lst)(dvessential-prime-implicants)(display-nl"function expressed by essential prime implicants ?")(dvfeepi)essential-prime-implicants);; e element;; s set;; sos set of sets(define(put-elements-of-set-of-sets-in-minterms-htsos)(map;; deal with sets of the 'set of sets'(lambda(s)(map;; deal with elements of a set(lambda(e){minterms-ht[e]<-#f})s))sos));; unify function for two minterms;;;; (function-unify-two-minterms-and-tag '(1 0 0 0) '(1 0 1 0)) -> '(1 0 x 0)(define(function-unify-two-minterms-and-tagmt1mt2){res⥆(unify-two-mintermsmt1mt2)}(whenres{minterms-ht[mt1]<-#t}{minterms-ht[mt2]<-#t})res);; (init-hash-table-with-set-and-value ht '((1 0 0 0) (0 1 0 1) (1 0 1 0) (1 1 0 0) (0 1 1 1) (1 1 0 1) (1 1 1 0) (1 1 1 1)) #f);; '(#<void> #<void> #<void> #<void> #<void> #<void> #<void> #<void>);; > ht;; '#hash(((1 1 0 1) . #f);; ((1 1 0 0) . #f);; ((0 1 0 1) . #f);; ((0 1 1 1) . #f);; ((1 0 0 0) . #f);; ((1 1 1 1) . #f);; ((1 1 1 0) . #f);; ((1 0 1 0) . #f));; used by Quine - Mc Cluskey(define(init-hash-table-with-set-and-valuehtsval)(display"init-hash-table-with-set-and-value")(newline){ht←(make-hash-table)}(map(lambda(e){ht[e]<-val})s)(display"end of init-hash-table-with-set-and-value")(newline));; list of non expressed minterms{non-expressed-minterms⥆'()};; could also be done with (declare non-expressed-minterms);; iepi : identifying essential prime implicant array;; first line : minterms;; first row : prime-implicants;; for now i do not know the array dimension(declareiepilgt-pilgt-mt);; example part of output:;; {iepi[1 2]} = 0;; {iepi[1 2] ← 1} = 1;; #(() (0 0 0 0) (0 0 0 1) (0 0 1 0) (1 0 0 0) (0 1 0 1) (0 1 1 0) (1 0 0 1) (1 0 1 0) (0 1 1 1) (1 1 1 0));; #(0 0 0 0 0 0 0 0 0 0 0);; #(0 1 0 0 0 0 0 0 0 0 0);; #(0 0 0 0 0 0 0 0 0 0 0);; #(0 0 0 0 0 0 0 0 0 0 0);; #(0 0 0 0 0 0 0 0 0 0 0);; #(0 0 0 0 0 0 0 0 0 0 0);; iepi = ;; #(() (0 0 0 0) (0 0 0 1) (0 0 1 0) (1 0 0 0) (0 1 0 1) (0 1 1 0) (1 0 0 1) (1 0 1 0) (0 1 1 1) (1 1 1 0));; #((0 x 0 1) * * );; #((0 1 x 1) * * );; #((0 1 1 x) * * );; #((x x 1 0) * * * (*));; #((x 0 0 x) * * * (*) );; #((x 0 x 0) * * * * )(define(identify-essential-prime-implicantsprime-implicantsminterms){vct-prime-implicants⥆(list->vectorprime-implicants)}{essential-prime-implicants-list⥆'()}{cpt-mt⥆0};; counter of minterms{y-pos-epi⥆0};; position of essential prime implicant in colomn if there exists one{star-in-column⥆#f};; at the beginning{lgt-pi←(lengthprime-implicants)}{lgt-mt←(lengthminterms)};; identifying essential prime implicant array;; first line : minterms;; first row : prime-implicants{iepi←(make-array-2d(+lgt-mt1)(+lgt-pi1)0)};; two dimensions array{iepi[0]←(list->vector(cons'()minterms))};; set the title line;; construction of the array;; set the left column containing prime implicants (for(y0(-lgt-pi1)){iepi[0(+y1)]←{vct-prime-implicants[y]}});; identify prime implicants(for(x1lgt-mt){cpt-mt←0}(for(y1lgt-pi)(if(compare-minterm-and-implicant{iepi[0y]}{iepi[x0]});; then($(incfcpt-mt)(when(=1cpt-mt){y-pos-epi←y});; position of essential prime implicant{iepi[xy]←" * "});; else{iepi[xy]←" "}));; end for y(when(=1cpt-mt);; essential prime implicant{iepi[xy-pos-epi]←"(*)"};; add essential prime implicant to list{essential-prime-implicants-list←(cons{iepi[0y-pos-epi]}essential-prime-implicants-list)}));; end for x{essential-prime-implicants-list←(remove-duplicatesessential-prime-implicants-list)}{feepi←#t};; check if function is expressed by essential implicants(for/breakbreak-x(x1lgt-mt);; loop over minterms(for/breakbreak-y(y1lgt-pi);; loop over prime implicants;; check wether prime implicant is an essential one?(when(member{iepi[0y]}essential-prime-implicants-list);; is the essential prime implicant expressing this minterms?(when(or(string=?{iepi[xy]}"(*)")(string=?{iepi[xy]}" * ")){star-in-column←#t}(break-y))));; that's enought! we know the minterm is expressed.;; end for/break break-y(unlessstar-in-column{feepi←#f};; function non expressed by prime implicants;; add minterm to non expressed minterms list{non-expressed-minterms←(insert{iepi[x0]}non-expressed-minterms)};;(break-x) ;; removed break-x as we have to check all the minterms now){star-in-column←#f});; set it for the next loop;; end for/break break-xessential-prime-implicants-list)