-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathA-Introduction-to-newLISP.lisp
8500 lines (6361 loc) · 271 KB
/
A-Introduction-to-newLISP.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; +=========================+
; | Introduction to newLISP |
; +=========================+
;
; Original version:
; http://en.wikibooks.org/wiki/Introduction_to_newLISP
; License:
; Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
; Original version creator: Cormullion
; This version creator: cameyo
; This document is based on:
; "Introduction to newLISP" (by Cormullion)
; (this is a modified/reduced text version with max row length = 100)
; All the errors are mine.
; Some infos from:
; "official newLISP forum"
; "Kazimir Majorinc blog"
; "Cormullion blog"
; Advantage of this version:
; - all the source in plain text
; - execute the code when reading tutorial (from within the editor)
; - add and try your comment/code to better understand
; the semicolon ";" is the comment character
; ";->" is a way of saying "the output is"
; Y combinator
; Y = λf.(λx.f(xx))(λx.f(xx))
; MULTI-LINE CODE IN REPL
; =======================
; 1) by enclosing the lines between [cmd] and [/cmd] OR
; 2) use the enter key on a blank line to begin and also to end the multi-line block.
(define (doppio x)
(mul x x))
[cmd]
(define (doppio x)
(mul x x))
[/cmd]
(define (fibonacci n)
(if (< n 2)
1
(+ (fibonacci (- n 1)) (fibonacci (- n 2)))))
(div (time (fibonacci 20) 100) 100.0)
; newLISP-GS provides a graphical toolkit for newLISP applications.
; You can edit newLISP scripts in your favourite text editor.
; You can use npp-newLISP.ahk on windows.
; Use (exit) to quit newLISP REPL.
; ==============================================================
; INDEX
; ==============================================================
; Introduction to newLISP
; Welcome to newLISP
; Resources
;
; The basics
; Downloading and installation
; Using newLISP with notepad++
; Getting started
; The three basic rules of newLISP
; Rule 1: a list is a sequence of elements
; Rule 2: the first element in a list is special
; Rule 3: Quoting prevents evaluating
; Symbols and Quote
; Setting and define Symbols
; Destructive functions
;
; Controlling the flow
; Tests: "if" statement
; Looping
; Working through a list "dolist"
; Working through a string "dostring"
; A certain number of time ("dotimes" and "for")
; Breaking loops
; Until something happens or while something is true
; Blocks: groups of expressions ("begin", "or", "and")
; Random expressions: the "amb" function
; Selection: "if", "cond", and "case"
; Local variables
; Make your own functions
; Local and Global variables
; Default values for parameters
; Arguments: "args"
; Other function to control the flow of code
; Scope of variables
;
; Lists
; Funtions to build lists
; Make a destructive function non-destructive
; Working with whole lists
; List analysis: testing and searching
; Finding items on a list
; Filtering lists: "filter", "clean", and "index"
; Testing lists
; Searching on lists
; Summary: compare and contrast
; Selecting items from lists
; Picking elements: "nth", "select", and "slice"
; Implicit addressing
; Selecting elements using implicit addressing
; Selecting slice using implicit addressing
; List surgery
; Shortening Lists
; Changing items in lists
; Replacing information: "replace"
; Modifying lists
; Find and replace matching elements: "set-ref"
; Find and replace all matching elements: "set-ref-all"
; Working with two or more lists
; Association lists
; Replaces sublists in association lists
; Adding new items to association lists
; "find-all" and association lists
;
; Strings
; Strings in code
; Making strings
; String surgery
; Substring
; String slices
; Changing the ends of strings
; "push" and "pop" work on strings too
; Modifying strings
; Using index numbers in strings
; Changing substrings
; Regular expressions
; System Variables $0, $1, ...
; The replacement expression
; Testing and comparing strings
; Strings to lists
; Parsing strings
; Other string functions
; Formatting strings
; Strings that make newLISP think
;
; Apply and map: applying functions to lists
; Making functions and data work together
; "apply" and "map" in more detail
; Write one in terms of the other?
; More tricks
; Lispiness
; Currying
;
; Introducing contexts
; What is a context?
; Contexts: the basics
; Creating contexts implicitly
; Functions in context
; The default function
; Passing parameters by reference
; Functions with a memory
; Dictionaries and tables
; Saving and loading contexts
; Using newLISP modules
; Scoping
; Objects
; FOOP in a nutshell
; Polymorphism
; Modifying objects
;
; Macros
; Introducing macros
; When do things get evaluated
; Tools for building macros
; Symbol confusion
; Other ideas for macro
; A Tracer macro
;
; Working with numbers
; Integers and floating-point numbers
; Integer and floating-point maths
; Conversions: explicit and implicit
; Invisible conversion and rounding
; Number testing
; Absolute signs, from floor to ceiling
; Number formatting
; Format Cheat Sheet
; Number utilities
; Creating numbers
; Sequences and series
; Random numbers
; Randomness
; General numbers tools
; Floating-point utilities
; Trigonometry
; Arrays
; Functions available for arrays
; Getting and setting values
; Matrices
; Statistics, financial, and modelling functions
; Bayesian analysis
; Financial functions
; Logic programming
; Bit operators
; Bigger numbers
;
; Working with dates and times
; Date and time functions
; The current time and date
; Reading dates and times: "parse-date"
; Timing and timers
;
; Working with files
; Interacting with the file system
; File information
; File management
; Reading and writing data
; Standard Input and output
; Command line arguments
;
; Working with pipes, threads, and processes
; Processes, pipes, threads, and system functions
; Multitasking
; Forked processes
; Reading and writing to threads
; Communicating with other processes
; Working with XML
; Converting XML into lists
; Changing SXML
; Outputting SXML to XML
; A simple practical example
;
; The debugger
;
; The internet
; HTTP and networking
; Accessing web pages
; A simple HTML Form
; A simple IRC client
;
; More examples
; On your own terms
; Using a SQLite database
; Querying the data
; Simple countdown timer
; Editing text files in folders and hierarchies
;
; Graphical interfaces
; Introduction
; A simple application
; Source code
; ==============================================================
; INTRODUCTION TO newLISP
; =======================
; WELCOME TO NEWLISP
; ==================
; RESOURCES
; =========
; THE BASICS
; ==========
; DOWNLOADING AND INSTALLATION
; ============================
; Download from: http://www.newlisp.org/
; Install following the instructions on the site.
; USING newLISP WITH NOTEPAD++
; ============================
; GETTING STARTED
; ===============
; Launch the newLISP REPL (newlip.exe on windows)
; THE THREE BASIC RULES OF NEWLISP
; ================================
; ==========================================================================
; RULE 1
; A LIST IS A SEQUENCE OF ELEMENTS ENCLOSED IN PARENTHESES.
; ==========================================================================
; a list of integers
'(1 2 3 4 5)
; a list of strings
'("the" "cat" "sat")
; a list of symbol names
'(x y z foo bar)
; a list of newLISP functions
'(sin cos tan atan)
; a mixed list
'(1 2 "stitch" x sin)
; a list with a list inside it
'(1 2 (1 2 3) 3 4 )
; a list of lists
'((1 2) (3 4) (5 6))
; ==========================================================================
; RULE 2
; THE FIRST ELEMENT IN A LIST IS SPECIAL.
; newLISP TREATS THE FIRST ELEMENT AS A FUNCTION AND THEN TRIES
; TO USE THE REMAINING ELEMENTS AS PARAMETERS OF THE FUNCTION.
; ==========================================================================
; sum of integers
(+ 10 22 12 34 88)
;-> 166
(+ 1.2 3.2)
;-> 4
; sum of floats
(add 1.2 3.2)
;-> 4.4
; There is no (reasonable) limit to the length of the list.
; newLISP has over 380 functions:
(directory "c://")
(directory "/")
(read-file "e://demo.txt")
; ------------------------------------------
; Every newLISP expressions returns a value.
; ------------------------------------------
; ==========================================================================
; RULE 3
; QUOTING PREVENTS EVALUATING.
; USE THE VERTICAL APOSTROPHE (ASCII CODE 39) TO QUOTE LISTS AND SYMBOLS.
; ==========================================================================
(+ 2 2)
;-> 4
'(+ 2 2)
;-> (+ 2 2)
; SYMBOLS AND QUOTES
; ==================
; A symbol is a newLISP thing with a name.
; You define something in your code and assign a name to it.
; Then you can refer to that something, using the name rather than the contents.
(set 'alphabet "abcdefghijklmnopqrstuvwxyz")
;-> "abcdefghijklmnopqrstuvwxyz"
(upper-case alphabet)
;-> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
(print alphabet)
; newLISP hasn't permanently changed the value of the symbol,
; because upper-case always creates and returns a new string,
; leaving the one stored in the symbol unchanged.
; Symbols correspond to variables in other programming languages.
; SETTING AND DEFINE SYMBOLS
; ==========================
; There are various ways to create and set the value of symbols.
; You can use "define" or "set".
(set 'x (+ 2 2))
;-> 4
(define y (+ 2 2))
;-> 4
; "set" expects to be followed by a symbol, but evaluates its first argument first.
; So you should either quote a symbol to prevent it being evaluated,
; or supply an expression that evaluates to a symbol.
; "define" doesn't expect the argument to be quoted.
; You can also use "setf" and "setq" to set the value of symbols.
; These expect a symbol or a symbol reference as the first argument,
; so you don't have to quote it.
(setf y (+ 2 2))
;-> 4
(setq y (+ 2 2))
;-> 4
; These two functions (which have the same action) can "set" the contents of
; a "symbol" (variable), a list, an array, or a string.
; Use "setq" when setting a symbol.
; Use "setf" when setting an element of a list or array.
; "define" is also used to define functions.
; DESTRUCTIVE FUNCTIONS
; =====================
; Some newLISP functions modify the values of the symbols that they operate on,
; others create a copy of the value and return that.
; The ones that modify the contents of symbols are described as destructive functions,
; although you'll often be using them to create new data.
; In this document I'll describe functions such as "push" and "replace" as destructive.
; This simply means that they change the value of something rather than return a modified copy.
; CONTROLLING THE FLOW
; ====================
; true and false
; nil -> false
; () -> false
; but "nil" is different from "()":
(= 'nil '())
;-> nil
; Anything that newLISP doesn't know the value of is false .
; Other values are true.
; (keyword expr1 expr2 ... exprN)
; TEST: if STATEMENT
; ==================
(set 'x 10)
(if (< x 0) (print "minore di zero"))
;-> nil
(if x 1)
; if x is true, return the value 1
(if 1 (launch-missile))
; missiles are launched, because 1 is true
(if 0 (launch-missile))
; missiles are launched, because 0 is true
(if nil (launch-missile))
;-> nil, there's no launch, because nil is false
(if '() (launch-missile))
;-> (), and the missiles aren't launched
; You can use anything that evaluates to either true or false as a test:
(if (> 4 3) (launch-missile))
;-> it's true that 4 > 3, so the missiles are launched
(if (> 4 3) (println "4 is bigger than 3"))
; If a symbol evaluates to nil (because it doesn't exist or hasn't been assigned a value),
; newLISP considers it false and the test returns nil
; (because there was no alternative action provided):
(if snark (launch-missile))
;-> nil ; that symbol has no value
(if boojum (launch-missile))
;-> nil ; can't find a value for that symbol
(if untrue (launch-missile))
;-> nil ; can't find a value for that symbol either
(if false (launch-missile))
;-> nil
; never heard of it, and it doesn't have a value
; You can add a third expression, which is the else action.
; If the test expression evaluates to nil or (), the third expression is evaluated,
; rather than the second, which is ignored:
(if x 1 2)
; if x is true, return 1, otherwise return 2
(if 1
(launch-missile)
(cancel-alert))
; missiles are launched
(if nil
(launch-missile)
(cancel-alert))
; alert is cancelled
(if false
(launch-missile)
(cancel-alert))
; alert is cancelled
(if (and socket (net-confirm-request)) ; test
(net-flush) ; action when true
(finish "could not connect")) ; action when false
; You can use if with an unlimited number of tests and actions.
; In this case, the if list consists of a series of test-action pairs.
; newLISP works through the pairs until one of the tests succeeds,
; then evaluates that test's corresponding action.
(if
(< x 0) (define a "impossible")
(< x 10) (define a "small")
(< x 20) (define a "medium")
(>= x 20) (define a "large")
)
; This is a simple alternative to "cond", the conditional function.
; newLISP provides the traditional "cond" structure as well.
(define (menu option)
(cond
((= option 1) (setq a 10) (println "1"))
((= option 2) (setq a 20) (println "2"))
((> option 1) (setq a 30) (println "3"))
(setq error "bad selection")
)
)
; To do two or more actions if a test is successful or not, you can use "when",
; which is like an "if" without an 'else' part.
(when (> x 0)
(define a "positive")
(define b "not zero")
(define c "not negative"))
; When newLISP sees a list, it treats the first element as a function.
; It evaluates the first element, before applying it to the arguments:
(define x 1)
((if (< x 5) + *) 3 4) ; which function to use, + or *?
;-> 7 ; it added
(define x 10)
((if (< x 5) + *) 3 4)
;-> 12 ; it multiplied
; In newLISP every expression returns some value, even an if expression:
(define x (if flag 1 -1)) ; x is either 1 or -1
(define result
(if
(< x 0) "impossible"
(< x 10) "small"
(< x 20) "medium"
"large"))
; LOOPING
; =======
; Repeat a series of actions more than once:
; - on every item in a list
; - on every item in a string
; - a certain number of times
; - until something happens
; - while some condition prevails
; newLISP has a solution for all of these, and more.
; WORKING THROUGH A LIST "dolist"
; ===============================
(define counter 1)
(dolist (i (sequence -5 5))
(println "Element " counter ": " i)
(inc counter)) ; increment counter by 1
; Unlike "if", the "dolist" function lets you write a series of expressions one after the other.
; Here both the "println" and the "inc" functions are called for each element of the list.
; newLISP automatically maintains a loop counter for you, in a system variable called $idx:
(dolist (i (sequence -5 5))
(println "Element " $idx ": " i))
; You can use the mapping function "map" for processing a list.
; "map" can be used to apply a function (either an existing function or a temporary definition)
; to every element in a list, without going through the list using a local variable.
(map sqrt '(1 2 3 4))
;-> (1 1.414213562373095 1.732050807568877 2)
(define counter 0)
(map (fn (i) (println " Element " counter ": " i)
(inc counter))
(sequence -5 5))
; "fn" is a synonym for "lambda".
; Another function to work on all the elements of a list is "apply".
; It applies a function (primitive, user-defined, or lambda expression) to the arguments in list.
(apply add '(1.2 3.4 4.5))
; The next example shows how apply's reduce functionality can be used
; to convert a two-argument function into one that takes multiple arguments.
;; find the greatest common divisor of two or more integers
;; note that newLISP already has a gcd function
(define (gcd_ a b)
(let (r (% b a))
(if (= r 0) a (gcd_ r a))))
(define-macro (my-gcd)
(apply gcd_ (map eval (args)) 2))
(my-gcd 12 18 6)
(my-gcd 1200 282823283 2341237618 232326 433332)
; Improper divisor function (for fun)
(define (improper-divisor n) (unique (cons n (factor 10))))
(improper-divisor 100)
(improper-divisor 16)
; To flattening a list use "flat"
(set 'a '(1 2 (3 4) (5 (6 7))))
(flat a)
;-> (1 2 3 4 5 6 7)
; To work through the arguments supplied to a function, you can use the "doargs" function.
; WORKING THROUGH A STRING ("dostring")
; =====================================
(define alphabet "abcdefghijklmnopqrstuvwxyz")
(dostring (letter alphabet)
(print (char letter) { } ))
; A CERTAIN NUMBER OF TIMES ("dotimes" AND "for")
; ===============================================
(dotimes (c 10)
(println c " times 3 is " (* c 3)))
; You must supply a local variable with these forms.
; Even if you don't use it, you have to provide one.
; Counting starts at 0 and continues to n - 1, never actually reaching the specified value.
; Use "for" when you known how many repetitions should be made, given start, end, and step values:
(for (c 1 -1 .5)
(println c))
; BREAKING LOOP
; =============
; You can use a test expression to break the loop:
(define number-list '(100 300 500 701 900 1100 1300 1500))
; first version
(dolist (n number-list)
(println (/ n 2)))
; second version
; Stops looping if the test for n being odd, (!= (mod n 2) 0), returns true.
(dolist (n number-list (!= (mod n 2) 0)) ; escape if true
(println (/ n 2)))
; You can supply escape route tests with "for" and "dotimes" too.
; UNTIL SOMETHING HAPPENS OR WHILE SOMETHING IS TRUE
; ==================================================
; Test for a situation that returns nil or () when something interesting happens,
; but otherwise returns a true value, which you're not interested in.
; To repeatedly carry out a series of actions until the test fails, use "until" or "do-until":
(until (disk-full?)
(println "Adding another file")
(add-file)
(inc counter))
(do-until (disk-full?)
(println "Adding another file")
(add-file)
(inc counter))
; In "until", the test is made first, then the actions in the body are evaluated if the test fails.
; In "do-until", the actions in the body are evaluated first, before the test is made,
; then the test is made to see if another loop is possible.
; "while" and "do-while" are the complementary opposites of "until" and "do-until",
; repeating a block while a test expression remains true.
(while (disk-has-space)
(println "Adding another file")
(add-file)
(inc counter))
(do-while (disk-has-space)
(println "Adding another file")
(add-file)
(inc counter))
; Choose the do- variants of each to do the action block before evaluating the test.
; BLOCKS: GROUPS OF EXPRESSIONS ("begin", "or", "and")
; ====================================================
(begin
(set 'a 10)
(set 'b 20)
(+ a b))
; Only the value of the last expression is returned, as the value of the entire block.
; "dotimes" or "dolist" constructions do not needs "begin",
; because these already allow more than one expression.
; The "and" function works through a block of expressions,
; but finishes the block immediately if one of them returns nil(false).
; To get to the end of the "and" block, every single expression has to return a true value.
; If one expression fails, evaluation of the block stops
; and newLISP ignores the remaining expressions,
; returning nil so that you know it didn't complete normally.
(and
(set 'a 10)
(set 'b 20)
(< a b)
(> a 0)
(/ b a)) ; I get here only if all tests succeeded
; The "or" function is more easily pleased than its counterpart "and".
; The expressions are evaluated one at a time until one returns a true value.
; The rest are then ignored.
; You could use this to work through a list of important conditions,
; where any one failure is important enough to abandon the whole enterprise.
; Or, conversely, use "or" to work through a list where any one success is enough to continue.
; Whatever, remember that as soon as newLISP gets a non-nil result, the "or" function completes.
(for (x -100 100)
(or
(< x 1) ; x mustn't be less than 1
(> x 50) ; or greater than 50
(> (mod x 3) 0) ; or leave a remainder when divided by 3
(> (mod x 2) 0) ; or when divided by 2
(> (mod x 7) 0) ; or when divided by 7
(println x)))
;-> 42
; RANDOM EXPRESSIONS: THE "amb" FUNCTION
; ======================================
; Given a series of expressions in a list, "amb" will choose and evaluate just one of them,
; but you don't know in advance which one.
; Use it to choose alternative actions at random:
(dotimes (x 20)
(amb
(println "Ho vinto!!!")
(println "Ho perso")
(println "Non so...")))
; SELECTION: "if", "cond", "case"
; ===============================
; To test for a series of alternative values, you can use "if", "cond", or "case".
; The "case" function lets you execute expressions based on the value of a switching expression.
; It consists of a series of match value/expression pairs:
(set 'n 3)
(case n
(1 (println "uno"))
(2 (println "due"))
(3 (println "tre"))
(4 (println "quattro"))
(true (println "diverso")))
; newLISP works through the pairs in turn, seeing if n matches any of the values 1, 2, 3, or 4.
; As soon as a value matches, the expression is evaluated and the "case" function finishes,
; returning the value of the expression.
; It's a good idea to put a final pair with true
; and a catch-all expression to cope with no matches at all.
; n will always be true, if it's a number, so put this at the end.
; The potential match values are not evaluated.
; If you prefer to have a version of case that evaluates its arguments, create a macro.
; A "cond" statement in newLISP has the following structure:
; (cond
; (test action1 action2 etc)
; (test action1 action2 etc)
; (test action1 action2 etc)
; ; ...
; )
; Where each list consists of a test followed by one or more expressions
; or actions that are evaluated, if the test returns true.
; newLISP does the first test, does the actions if the test is true,
; then ignores the remaining test/action loops.
; Often the test is a list or list expression, but it can also be a symbol or a value.
(cond
((< x 0) (define a "impossible") )
((< x 10) (define a "small") )
((< x 20) (define a "medium") )
((>= x 20) (define a "large") )
)
; The version with "if";
(if
(< x 0) (define a "impossible")
(< x 10) (define a "small")
(< x 20) (define a "medium")
(>= x 20) (define a "large")
)
; If you want the action for a particular test to evaluate more than one expression,
; cond's extra set of parentheses can give you shorter code:
(cond
((< x 0) (define a -1) ; if would need a begin here
(println a) ; but cond doesn't
(define b -1))
((< x 10) (define a 5))
)
; LOCAL VARIABLES
; ===============
; Using "let" and "letn" functions, you can define variables that exist only inside a list.
; They aren't valid outside the list,
; and they lose their value once the list has finished being evaluated.
; The first item in a let list is a sublist containing variables (which don't have to be quoted)
; and expressions to initialize each variable.
; The remaining items in the list are expressions that can access those variables.
; It's a good idea to line up the variable/starting value pairs:
(let
(x (* 2 2)
y (* 3 3)
z (* 4 4))
; end of initialization
(println x)
(println y)
(println z))
; If you want to refer to a local variable elsewhere in the first initialization section
; use "letn" rather than "let":
(letn
(x 2
y (pow x 3)
z (pow x 4))
(println x)
(println y)
(println z))
; MAKE YOUR OWN FUNCTIONS
; =======================
; The basic structure of a function definition is like this:
;
; (define (func1)
; (expression-1)
; (expression-2)
; ...
; (expression-n)
; )
;
; (define (func1 v1 v2 ... vn)
; (expression-1)
; (expression-2)
; ...
; (expression-n)
; )
; When the function is called, each expression in the body is evaluated in sequence.
; The value of the last expression to be evaluated is returned as the function's value.
(define (is-3? n)
(= n 3))
(is-3? 2)
;-> nil
(is-3? 3)
;-> true
; If you want to explicitly specify the value to return,
; add an expression at the end that evaluates to the right value:
(define (bigger a b)
(set 'out (> a b))
(set 'delta (- a b))
out)
(bigger 2 3)
; To make a function return more than one value, you can return a list.
; newLISP is smart to check the function parameters:
(define (test n)
(println n))
(test) ; no n supplied, so print nil
;-> nil
(test 1)
;-> 1
(test 1 2 3) ; 2 and 3 ignored
;-> 1
; Symbols that are defined in the function's argument list are local to the function,
; even if they exist outside the function.
; LOCAL AND GLOBAL VARIABLES
; ==========================
; Use "let" or "letn" to define a local variable,
; which doesn't affect its symbol outside the function:
(define x 10)
(define y 20)
(define (testxy)
(let (x 15)
(println "my x is " x))
(set 'y 25)
(println "my y is " y)
)
(testxy)
;-> my x is 15
;-> my y is 25
(println "outside x is " x)
;-> outside x is 10
;-> outside y is 25
(println "outside y is " y)
; Instead of "let" and "letn" you can use the "local" function.
; In this case you don't have to supply any values for the local variables.
; They're just nil until you set them:
(define (test)
(local (a b c)
(println a " " b " " c)
(set 'a 1 'b 2 'c 3)
(println a " " b " " c)))
(test)
;-> nil nil nil
;-> 1 2 3
(define a 10)
(define b 20)
(define c 30)
(define (test a b c)
(println a " " b " " c)
(set 'a 1 'b 2 'c 3)
(println a " " b " " c))
(test 100 200 300)
;-> 100 200 300
;-> 1 2 3
; The comma "," is a symbol too:
(set ', "Simbolo")
(println ,)
; DEFAULT VALUES FOR PARAMETERS
; =============================
; The local variables defined in the function's argument list can have default values,
; which will be used if you don't specify values when you call the function.
(define (test (a 1) b (c 2))
(println a " " b " " c))
; The symbols a and c will take the values 1 and 2 if you don't supply values in the call,
; but b will be nil unless you supply a value for it.
(test)
;-> 1 nil 2
; ARGUMENTS: "args"
; =================
; You can write definitions that accept any number of arguments.
(define (test v1)