-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathD-Kazimir-Blog.lisp
16413 lines (13532 loc) · 620 KB
/
D-Kazimir-Blog.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
=======================
KAZIMIR MAJORINC BLOG
=======================
In questo documento sono presentati alcuni post del blog di Kazimir Majorinc presenti nel sito:
http://kazimirmajorinc.blogspot.com/
Kazimir è un vero esperto sul linguaggio LISP e approfondisce in modo molto interessante alcune caratteristiche di newLISP (in particolar modo quelle proprie della famiglia dei linguaggi LISP).
Alcune parti del codice di esempio sono state aggiornate alla versione 10.7.5 di newLISP.
I sorgenti e i commenti ai post non sono stati tradotti.
Tutti i diritti sono di Kazimir Majorinc.
Indice degli articoli
---------------------
Starting with newLISP
Embedding blocks into Functions
Evaluation of Large Expressions in Newlisp
Eval and Anti-eval
Promote Your Functions!
Assignment Macro Beast Unleashed
Does the Function Really Evaluate to Itself?
New Copies Discovered
If lambda Gives let, What About lambda-macro?
Verbose Functions and Macros
On Calling and Applying Newlisp Functions and Macros
Conversions to Functions and Macros
Speed of The Evaluation vs. Length of The Names of The Variables
Exploring The Reference
Three Techniques for Avoidance of Multiple Copies
For-like Syntax for Rnd Function and Generalized Floor and The Friends
Light Your Pipe
Two Phases Evaluation
The Predicates =?, >? and Friends
Majorinc.default-library.lsp uploaded
Macrocall
Don't Fear Dynamic Scope
Don't Fear Dynamic Scope (2)
Swap Without Temporary Variable
Short or Long Function Names?
Avoiding Function Names Clashes
Two Definitions of IF Function
Challenged by Common Lispers
Test for Unnecessary Arguments
Calculate or Ask
Apply Has Its Secrets Too
Random Sublists
Trees, Branches and Leaves
The Most Probable Cond
More on Usenet and Google Groups Posting Frequency
Where is Letex!
Multiple Loops
Add and Multiply Digits
The First Use of Identity Function
Text Titles
Quote is Identity Fexpr
Gensym and Genlet
Genlocal
Genloops
Supernatural Symbols
On Macros, Eval and Generated Code in Lisp
Crawler Tractor
Supressed Printing
On Serial Substitution and Not Reading The Manual
Propositional Variables and Formulas
Reader Macros in Newlisp?
eval-string or eval?
Random Propositional Formulas of a Given Average Length
On Expected Truth Value of a Random Propositional Formula
On Expected Truth Value of a Random Propositional Formula (2)
The Probability That Random Propositional Formula is Tautology
Lists of Propositional Formulas
Debug-wrapping Around Built-in Primitives
One Hundred Propositional Tautologies (1)
One Hundred Propositional Tautologies (2)
Opinions on Eval in Lisp, Python and Ruby - The Result of The Pool
Why You Do Not Use Lisp? The Results of The Poll
One Hundred Propositional Tautologies (3)
One Hundred Propositional Tautologies (4)
One Hundred Propositional Tautologies (5)
Tortelvis
Relatively Short Propositional Formulas and Symbols Instead of Pointers and Tables
Symbols as Sexprs and Hygienic Fexprs
Alan Kay on Lisp and Fexprs
Composition of Functions or Macros
Composing Fexprs Preserves Short-circuit Evaluation.
How many syllogisms are there?
The program for derivation of syllogisms, condense...
McCarthy - Dijkstra short polemics in 1976.
Interesting Case of Mismatched Parentheses.
Short notes on McCarthy's "Recursive Functions ... "
Using (sin cos 0.5) instead of (sin (cos 0.5)) in Newlisp
McCarthy's 1960 "Recursive Functions ..." Lisp in Newlisp
McCarthy-60 Lisp Implemented as Association List in McCarthy-60 Lisp
McCarthy-60 Lisp in McCarthy-60 Lisp in ... in McCarthy-60 Lisp.
On Pitman's "Special forms in Lisp"
Lambda Calculus Interpreter
Expansion of Free Variables
Do You Need Five Hundred Random Lambda-Expressions?
In Search for The Irreducible Lambda-Expressions
Cantor's Enumerations (1)
Cantor's Enumerations (2)
Cantor's Enumerations (3)
Enumeration of Lambda-Expressions
199019 Reduced Lambda-Expressions
Lambda Calculus Interpreter (2)
Some differences between lambda-calculus and Lisp (1)
Some differences between lambda-calculus and Lisp (2)
Some Basic Concepts Implemented and Reduced in Lambda-calculus
Lambda Calculus Meta-variables Supported in my Newlisp Library
Parallel "Expand"
Conflation of Subtraction and Additive Inverse in Lisp
Tangent
More Sophisticated Encoding of S-exprs into Symbols.
Another Encoding of S-expressions in Symbols
Implementing Data Structures with Symbols
Three meanings of the term 'S-expression'
The Similarities Between Axioms of Natural Numbers and Axioms of S-expressions
------------------------------------------------------------------------------
---------------------
Starting with newLISP
---------------------
http://kazimirmajorinc.blogspot.com/2008/05/starting-with-newlisp-blog.html
Ho deciso che nei prossimi mesi, e forse più a lungo, utilizzerò il linguaggio di programmazione newLISP. Il motivo principale è che ho riconosciuto alcune caratteristiche importanti coerenti con i principali obiettivi di progettazione di Lisp e, credo, forniscono funzionalità potenti e astratte che rendono i problemi algoritmici complessi, in particolare i problemi di intelligenza artificiale più facili da risolvere. Negli ultimi decenni, sembra che i dialetti Lisp abbiano trascurato lo sviluppo della lingua centrale, invece, gli sforzi sembrano essere investiti principalmente nella produzione di implementazioni più adatte all'uso pratico.
Valutazione (eval) senza limitazioni
------------------------------------
La funzione "eval" è la pietra angolare del paradigma "code=data" per cui Lisp è noto. Se il codice viene trattato come dati, significa che può essere elaborato e valutato durante il runtime. La valutazione del codice è fornita attraverso l'applicazione della funzione "eval" sulla pace del codice. In qualche modo sorprendentemente, sia Common Lisp che Scheme implementano una versione in qualche modo ristretta di eval, ovvero una che non vede "variabili locali". La valutazione di newLISP non è limitata in questo modo.
(let ((a 1) (b 2))
(println (eval '(+ a b))))
Questo codice restituisce 3 in newLISP, mentre in altri dialetti Lisp questo codice produce l'errore "variabile non definita/non associata". Alcuni utenti Lisp affermano che eval senza restrizioni impedisce alcune ottimizzazioni durante la compilazione del codice. Forse - ma affermare che qualche caratteristica astratta dovrebbe essere scartata perché lenta è stranamente radicale e ingiustificata: si può semplicemente usarla quando il tempo non è critico, ed evitarla se lo è. Non penso che dovrebbe essere accettato come normale che linguaggi come Python abbiano "eval" più potenti di Common Lisp o Scheme.
Macro di prima classe
---------------------
Inoltre, newLISP ha macro semplici ma potenti. In newLISP, le macro sono proprio come le funzioni, tranne per il fatto che accettano argomenti non valutati. Sono "cittadini di prima classe", valori che possono essere utilizzati nelle espressioni ed essere il risultato della valutazione delle espressioni. Possono essere passati come argomenti e restituiti come risultati delle funzioni o di altre macro. Le macro newLISP sono più facili da scrivere perché possono eseguire direttamente determinate attività, invece di generare codice che eseguirà tale attività. Come puoi vedere nell'esempio seguente, non sono necessarie virgolette e virgole.
(set 'my-print (lambda-macro(x)
(print "(-> " x " " (eval x )")")))
(my-print (+ 3 7))
;-> (-> (+ 3 7) 10)
I vecchi Lisp, negli anni '70, avevano questa caratteristica. È stato chiamato fexpr ma è stato abbandonato a favore delle macro come le conosciamo in questi giorni.
La critica di Pitman a Fexpr
----------------------------
Da Wikipedia,
alla "Conference on Lisp and Functional Programming del 1980", Kent Pitman presentò un documento "Special Forms in Lisp" in cui discuteva i vantaggi e gli svantaggi di macro e feexprs e alla fine condannò fexprs. La sua obiezione centrale era che, in un dialetto Lisp che consente fexprs, l'analisi statica non può determinare generalmente se un operatore rappresenta una funzione ordinaria o un feexpr - quindi, l'analisi statica non può determinare se gli operandi verranno valutati o meno. In particolare, il compilatore non è in grado di stabilire se una sottoespressione può essere ottimizzata in modo sicuro, poiché la sottoespressione potrebbe essere trattata come dati non valutati in fase di esecuzione.
Questo è un argomento simile a quello per la restrizione di "eval". Non solo ignorare la potente funzionalità perché non può essere ottimizzata è una decisione ingiustificata, ma in questo caso particolare, non è nemmeno vero che fexpr non può essere ottimizzato. Se le fexpr Lisp (macro newLISP) sono scritte nello stesso stile delle macro Lisp equivalenti e le chiamate feexpr sono inline, allora forniscono esattamente le stesse opportunità di ottimizzazione delle chiamate macro Lisp. La valutazione delle chiamate macro di Common Lisp è separata in due fasi: macroespansione e valutazione del codice macroespanso. Di solito, anche se non sempre, l'espansione macro non dipende da alcun valore noto solo in runtime, quindi l'espansione macro può essere eseguita durante la fase di compilazione. Ma in tali casi, parti della chiamata fexpr equivalente e inline possono essere valutate e ottimizzate durante la fase di compilazione allo stesso modo. L'implementazione di newLISP non lo fa, è un interprete - nessun problema per me, tendo a non preoccuparmi per niente del processo di compilazione - ma tali ottimizzazioni sono tuttavia possibili.
Un altro motivo per cui Pitman preferisce le macro Lisp rispetto ai fexprs Lisp è che desidera una sorta di analisi automatica del codice. Ad esempio, supponiamo che si voglia definire la macro Lisp (USED-ON-PARTICULAR-WAY [variabile] [espressione]) che restituisce 1 se, beh, se [variabile] è usato sul modo particolare in [espressione], e 0 se non lo è. Se [espressione] contiene macro, queste macro possono essere espanse in USED-ON-PARTICULAR-WAY (usando MACROEXPAND di Common Lisp) e analizzate in modo che USED-ON-PARTICULAR-WAY possa trovare la risposta di cui ha bisogno. Non può essere fatto se [espressione] contiene fexprs invece di macro. Le fexprs sono come scatole nere e USED-ON-PARTICULAR-WAY non possono vedere cosa succede al loro interno. Pitman ha parzialmente ragione. In parte, perché non è escluso che [variabile] sia comunque utilizzata in modo particolare durante la fase di macroespansione, e non sia visibile nel codice macroespanso! Il codice macroespanso non contiene necessariamente tutte le informazioni rilevanti. Ma se supponiamo che l'analisi automatica della fase di macroespansione non sia necessaria, qualunque sia la ragione, sì, ha ragione. Tuttavia, le macro di newLISP risolvono anche questo problema e si rivelano ancora più "trasparenti" e adatte al tipo di analisi che sostiene. Ecco perché:
Funzioni e macro sono le loro definizioni
-----------------------------------------
In Common Lisp e Scheme, le funzioni sono tipi speciali di valori risultanti dalle valutazioni delle loro definizioni. Possono essere usati come valori e applicati, ma le loro definizioni non sono accessibili e non possono essere analizzati e modificati durante il runtime. In newLISP, le funzioni non sono risultati della valutazione delle definizioni, sono esattamente la stessa cosa delle loro definizioni. Quindi, possono essere analizzati (e mutati) durante il runtime. E lo stesso vale per le macro newLISP. L'esempio seguente dimostra tale funzionalità.
(set 'my-print (lambda-macro(x)
(print "(->" x " " (eval x ) ")" )))
(set 'replace-print-with-println
(lambda-macro(f)
(set-nth 1
(eval f)
(append '(println) (rest (nth 1 (eval f)))))))
(println my-print)
(replace-print-with-println my-print)
(println my-print)
; Output:
;(lambda-macro (x) (print "(->" x " " (eval x) ")"))
;(lambda-macro (x) (println "(->" x " " (eval x) ")"))
Quindi, sì, le macro newLISP e persino le funzioni newLISP possono essere analizzate da altre funzioni e macro, e questo è un miglioramento sostanziale nello spirito del paradigma "code=data".
Problemi del mondo reale
------------------------
newLISP è un nuovo linguaggio, sviluppato da un uomo, lo psicologo e scienziato informatico americano Lutz Mueller e ha una piccola comunità di utenti e contributori, quindi ha meno funzionalità rispetto ad alcune implementazioni mature di Common Lisp e Scheme. Tuttavia, nessuna delle funzionalità mancanti sembra essere essenziale per i miei programmi e, si spera, se il linguaggio stesso avrà successo, le librerie newLISP e le funzionalità native cresceranno. Sebbene abbiamo visto che newLISP supera altri dialetti Lisp in termini di potenza espressiva della lingua principale, l'autore afferma che il linguaggio è sviluppato principalmente "per essere utile per risolvere problemi del mondo reale" e che "cose come espressioni regolari, funzioni di rete e supporto per popolari protocolli come XML o HTTP sono tutti integrati in newLISP senza la necessità di librerie esterne." Alcuni utenti di newLISP affermano di aver attivato newLISP proprio per questo, non per le funzionalità astratte che ho elencato.
Gestione della memoria
----------------------
La mia unica preoccupazione è che newLISP non consente che le strutture dati condividano parti comuni in memoria. Altri utenti di Lisp lo menzionano spesso come un punto debole, e sembra così a prima vista. Tuttavia, in questo momento, non sono in grado di stimare tutte le conseguenze di quella politica, quindi mi baso sull'aspettativa che Mueller, che è stato in grado di migliorare da solo le basi del Lisp, non abbia commesso errori significativi in questa parte del linguaggio. Spero che imparerò come compensare questa limitazione. Una possibilità potrebbe essere nello sfruttamento dei fatti che le strutture dati possono, tuttavia, contenere gli stessi simboli e i simboli possono essere usati come riferimenti di strutture dati.
(set 'x (list 1 2))
(set 'a 'x)
(set 'b 'x)
(eval a)
;-> (1 2)
(setf ((eval a) 0) 2)
;-> 2
(eval a)
;-> (2 2)
x
;-> (2 2)
(print-expr-and-value-lns a b (eval a) (eval b))
;Results in:
;(-> a x)
;(-> b x)
;(-> (eval a) (2))
;(-> (eval b) (2))
Tornerò sicuramente sull'argomento nei prossimi mesi.
Commenti
--------
*** Anonymous9 May 2008 at 15:36
"... and symbols can be used as references of data structures"
Yes, and this is how you can do it in 9.3.0. A trivial example how to do reference passing:
(define foo:data '(a b c d e f))
(define (pop-last aList)
(pop aList:data -1))
(pop-last foo) => f
foo:data => (a b c d e)
Additionally in development version 9.3.11 and after you can do:
(define foo:foo '(a b c d e f))
(define (pop-last aList)
(pop aList -1))
(pop-last foo) => f
foo:foo => (a b c d e)
foo:foo is called the "default functor" (usage of the namespace name "foo" defaults to the symbol in it of the same name "foo:foo").
*** Anonymous9 May 2008 at 18:33
..previous commentator already said what I was going to add ;))
[1] I.e. if a symbol is declared as belonging to some "context", then newLISP keeps it as a static var, and its use in other expressions will automatically reuse "the same parts".
One can freely copy from a context-defined symbols. For example if I have a string a:string, then, say, some function
(reverse (string a:string))
which on the surface uses redundant cast into string of what is already a string in fact creates a COPY of the original a:string, and if this hypothetical reverse is destructive, it won't affect the original a:string.
No such trick - and you'll be changing the original.
[2] "Contexts" are in my view a nice and powerful instrument. Actually, each "context" is a "hash", to use a Perl term (a red-black tree), and can even get back its symbols in alphabetical order, which is sometimes nice for kind-of built-in sorting without extra overhead.
(see the "dotree" operator)
-------------------------------
Embedding Blocks into Functions
-------------------------------
http://kazimirmajorinc.blogspot.com/2008/05/embeding-blocks-into-functions.html
; I'm trying to "embed" blocks into functions or macros, they
; can be useful for calls similar to
;
; (help function)
; (test f)
;
; etc. There are lot of ways it can be done, for example, using
; contexts. Or closures where available. Or hash tables containing
; functions for tests and help. But i tried this one.
;---------------------------------------------------------------
; I want to use "function" and "macro" as keywords
; instead of "lambda" and "lambda-macro"
(set 'function
(lambda-macro()
(eval (append '(lambda) (args)))))
(set 'macro
(lambda-macro()
(eval (append '(lambda-macro) (args)))))
; Tests: later
;---------------------------------------------------------------
; One macro useful for printing. I learnt that I almost always
; use output in this form. In the same time, test for "macro"
(set 'expression-and-value
(macro(x)
(list '-> x (eval x))))
; Tests:
(println expression-and-value)
(println (expression-and-value (+ 3 3)))
; Results:
;(lambda-macro (x) (list '-> x (eval x)))
;(-> (+ 3 3) 6)
;---------------------------------------------------------------
; As expression-and-value is used almost exclusively in print
; and it is frequently used, it justifies definition of one
; special print functions, with a very short name.
; I'll use this name: §
(set '§ (macro()
(doargs(x)
(println (eval (list 'expression-and-value x))))))
; Test (it is enough to test §)
(set 'z 1)
(§ z (sin z) (+ z 4))
; Result:
;(-> z 1)
;(-> (sin z) 0.8414709848);
;(-> (+ z 4) 5)
;---------------------------------------------------------------
; I define block as non-empty list. Intention is to make
; generalization of begin-block. Following functions are very
; simple and they do not require any comments.
(set 'block?
(function(candidate)
(if (list? candidate)
(not (empty? candidate)))))
; Tests:
(§ (block? '(hello-world (println "hello, world"))))
(§ (block? '()))
(§ (block? 3))
(§ (block? '(nil print)))
; Results:
;(-> (block? '(hello-world (println "hello, world"))) true)
;(-> (block? '()) nil)
;(-> (block? 3) nil)
;(-> (block? '(nil print)) true)
;---------------------------------------------------------------
(set 'get-block-name
(function(some-block)
(if (not (block? some-block))
(throw-error (list "get-block-name applied on non-block"
some-block))
(first some-block))))
;Tests
(§ (get-block-name '(hello (println "hello"))))
;(§ (get-block-name '()))
;(§ (get-block-name 3))
; Results:
;(-> (get-block-name '(hello (println "hello"))) hello)
; other two really return excpected error
;---------------------------------------------------------------
(set 'quoted-block?
(function(candidate)
(if (quote? candidate)
(block? (eval candidate)))))
; Tests:
(§ (quoted-block? ''(hello (println "hello!"))))
(§ (quoted-block? ''()))
(§ (quoted-block? '3))
(§ (quoted-block? ''(nil print)))
; Results:
;(-> (quoted-block? ''(hello (println "hello!"))) true)
;(-> (quoted-block? ''()) nil)
;(-> (quoted-block? '3) nil)
;(-> (quoted-block? ''(nil print)) true)
;---------------------------------------------------------------
(set 'begin-block-from-any-block
(function(some-block)
(append '(begin)
(rest some-block))))
; Test:
(§ (begin-block-from-any-block
'(hello (println "Hello!"))))
; Result: works OK
;---------------------------------------------------------------
(set 'get-block-from-list-containing-quoted-blocks
(function(block-name list-containing-quoted-blocks)
(catch (dolist (i list-containing-quoted-blocks)
(if (and (quoted-block? i)
(= block-name
(get-block-name (eval i))))
(throw (eval i)))))))
; Tests:
(§ (get-block-from-list-containing-quoted-blocks
'test
(list ''(wrong) '(test) 0 ''(test) '(false))))
(§ (get-block-from-list-containing-quoted-blocks
'test
(list '(wrong) '(right) 0 '(false))))
(§ (get-block-from-list-containing-quoted-blocks
'test
(list)))
(§ (get-block-from-list-containing-quoted-blocks
'test
'()))
; Results: everything works OK
;---------------------------------------------------------------
(set 'evaluate-block-from-list-containing-quoted-blocks
(function (block-name list-containing-quoted-blocks)
(eval (begin-block-from-any-block
(get-block-from-list-containing-quoted-blocks
block-name
list-containing-quoted-blocks)))))
;---------------------------------------------------------------
; OK, everything is ready for a final test.
; I'll define one cute function, "integer-quote" with two cute
; blocks, "help" and "test," and see what happens.
(set 'integer-quote
(macro(i expr)
'(help
(println "\nInteger-guote help:")
(println " Syntax: (integer-quote <integer> <expression>)")
(println " Example: " (expression-and-value (integer-quote 2 x)))
(println " Example: " (expression-and-value (integer-quote -3 x)))
(println " Example: " (expression-and-value (integer-quote 0 x)))
(println "End of integer-quote help.\n"))
'(test
(println "\nInteger-quote test:")
(if (= (integer-quote 2 x) '(quote (quote x)))
(println " First test passed.")
(println " First test failed."))
(if (= (integer-quote -3 x) '(eval (eval (eval x))))
(println " Second test passed.")
(println " Second test failed."))
(if (= (integer-quote 0 x) 'x)
(println " Third test passed.")
(println " Third test failed."))
(println "End of quote-eval test.\n"))
(cond
((= i 0) expr)
((> i 0) (eval (list 'integer-quote
(- i 1)
(list 'quote expr))))
((< i 0) (eval (list 'integer-quote
(+ i 1)
(list 'eval expr)))))))
;---------------------------------------------------------------
; Tests
(println "\n\n\nOK, let me see how it works.")
(evaluate-block-from-list-containing-quoted-blocks 'help integer-quote)
(evaluate-block-from-list-containing-quoted-blocks 'test integer-quote)
(§ (integer-quote -7 (i-o-lets-go!)))
;Results
;Integer-guote help:
; Syntax: (integer-quote <integer> <expression>)
; Example: (-> (integer-quote 2 x) (quote (quote x)))
; Example: (-> (integer-quote -3 x) (eval (eval (eval x))))
; Example: (-> (integer-quote 0 x) x)
;End of integer-quote help.
;Integer-quote test:
; First test passed.
; Second test passed.
; Third test passed.
;End of quote-eval test.
;(-> (integer-quote -7 (i-o-lets-go!))
;(eval (eval (eval (eval (eval (eval (eval (i-o-lets-go!)))))))))
;Everything works fine.
;Sure, i can use shorter names.
------------------------------------------
Evaluation of Large Expressions in Newlisp
------------------------------------------
http://kazimirmajorinc.blogspot.com/2008/05/evaluation-of-large-expressions-in.html
; This time I'll try different eval benchmark; instead of
; evaluating simple expressions many time, I'll write the program
; that construct large s-expression and measures the time of its
; evaluation
(setq large-s-expression 1)
(setq counter 1)
(do-while (< counter 1000000)
(setq counter (+ counter 1))
(setq large-s-expression
(list 'eval
(list 'quote
(list '+ counter large-s-expression))))
(when (= (% counter 100) 0)
(println counter
" > "
(time (eval large-s-expression)))))
; This is how those z that are evaluated
; look like for counter=2,3,...
;(eval (quote (+ 2 1)))
;(eval (quote (+ 3 (eval (quote (+ 2 1))))))
;(eval (quote (+ 4 (eval (quote (+ 3 (eval (quote (+ 2 1)))))))))
; 100 > 0
; 200 > 15
; 300 > 15
; 400 > 31
; 500 > 46
; 600 > 78
; 700 > 109
; 800 > 140
; 900 > 234
; 1000 > 281
; 1100 >
; ERR: call stack overflow in function eval : quote
;
; Newlisp returns to REPL after that stack overflow. The speed
; is satisfactory, although it seems it is not stable, in some
; executions I got numbers like 900 ms for evaluation of the
; expression with 1000 evals.
; Also, stack overflow happens earlier than in other Scheme
; or Lisp implementations. Clisp and PLT stack overflow
; happens for counter = about 4000, Lispworks and Allegro (free
; editons somewhere near 50 000, while Petit Chez Scheme works
; happily for counter > 10 000 000 and more. Stack overflow
; results in crash of PLT IDE and Chez Scheme interpreter
; respectively.
; However, that stack overflow in Newlisp is not the result of
; eval and quote, because it happens even earlier if eval and
; quote are replaced with sin and cos.
; Conclusion: for evaluation of very large expressions, Newlisp
; is satisfactory, but there is a lot of room for improvement.
Commenti
--------
*** cormullion 18 May 2008 at 18:20
you could always change the stack size:
newlisp -s 100000
newLISP v.9.3.11 on OSX IPv4 UTF-8, execute 'newlisp -h' for more info.
>... your code
1
1
100 > 2
200 > 10
300 > 21
...
3600 > 6150
3700 > 22911
3800 > 113175
it gets very slow though... :)
------------------
Eval and Anti-eval
------------------
http://kazimirmajorinc.blogspot.com/2008/05/eval-and-anti-eval.html
;---------------------------------------------------------------
; I again need some functions and macros I already defined.
; For the rest of the text see bellow.
(set 'macro
(lambda-macro()
(eval (append '(lambda-macro) (args)))))
(set 'expression-and-value
(macro(expression-and-value-arg)
(list '->
expression-and-value-arg
(eval expression-and-value-arg))))
(set '§ (macro()
(doargs(§arg)
(println (eval (list 'expression-and-value §arg))))))
;---------------------------------------------------------------
;
; Eval and Anti-eval.
;
; Quote and eval can be seen as inverse functions;
; But, they are not exactly that:
(set 'x "I am the value of x")
(println (= x (quote (eval x)))) ; -> nil! UGLY! UGLY!
(println (= x (eval (quote x)))) ; -> true
; What really happens?
(§ (quote (eval x))) ;(-> (quote (eval x)) (eval x))
(§ (eval (quote x))) ;(-> (eval (quote x)) "I am the value of x")
; Say we want real inverse of eval, i.e. function anti-eval
; such that everything works as expected.
(set 'anti-eval
(macro(argument)
(if (and (list? argument)
(not (empty? argument))
(= (first argument) 'eval))
(eval (first (rest argument)))
argument)))
;Tests:
(§ (anti-eval (eval x)))
(§ (eval (anti-eval x)))
(§ (anti-eval (eval (quote (+ 2 3)))))
(§ (eval (anti-eval (quote (+ 2 3)))))
(§ (eval (anti-eval (eval (anti-eval x)))))
(§ (anti-eval (eval (anti-eval (eval x)))))
;Results:
;(-> (anti-eval (eval x)) "I am the value of x")
;(-> (eval (anti-eval x)) "I am the value of x")
;(-> (anti-eval (eval (quote (+ 2 3)))) (+ 2 3))
;(-> (eval (anti-eval (quote (+ 2 3)))) (+ 2 3))
;(-> (eval (anti-eval (eval (anti-eval x)))) "I am the value of x")
;(-> (anti-eval (eval (anti-eval (eval x)))) "I am the value of x")
;So far, so good.
;And even this one:
(§ (eval (anti-eval (anti-eval (eval x)))))
(§ (anti-eval (eval (eval (anti-eval x)))))
;(-> (eval (anti-eval (anti-eval (eval x)))) "I am the value of x")
;(-> (anti-eval (eval (eval (anti-eval x)))) "I am the value of x")
; But I wouldn't be surprised it is broken for more complicated
; expression. I'll keep an eye on it. But this is only blog.
; Is there any practical use of anti-eval? I don't know,
; but it would be strange that there is no use whatsoever.
Commenti
--------
*** cormullion 20 May 2008 at 17:44
Good post! These are very interesting ideas.
One question: Why do you say this:
(println (= x (quote (eval x)))) ; -> nil! UGLY! UGLY!
Why is this really ugly to you? To me (unburdened by knowledge of Common Lisp or Scheme), it looks like asking whether an evaluated symbol is equal to an unevaluated entity.
*** Kazimir Majorinc 21 May 2008 at 02:32
You are right, it has a perfect sense in Lisp and Newlisp.
It is ugly only because some inverse functions in mathematics behave on prettier way, i.e. exp and log, differentiation and integration. It is simpler to think about these pairs.
So, I was provoked by the question, is it possible to have something that is full left and right side inverse to eval.
And can it be useful?
Actually, answer on that last question is already known - it can, that is why CL and Scheme provide something similar, i.e
(= 3 (quasiquote (unquote 3))) ;=> true
i.e. quasiquote behave just as quote - except unquote - which is something similar to eval - is able to "fight against" quasiquote not from outside (like eval fight against quote) but from inside.
But, again, unquote cannot fight against quasiquote from outside.
(= 3 (unquote (quasiquote 3)) => ERROR.
However, eval can do that.
(= 3 (eval (quasiquote 3))) => true
I somehow think it also turned to be too complicated and there should be some generalized concept that on a mathematically elegant way covers all of the functionalities of quote, eval, quasiquote and unquote - and maybe beyond.
I just play a bit in that direction with this blog entry.
*** Kazimir Majorinc 21 May 2008 at 02:51
These examples of quasiquote are from Scheme, it is similar (but I'd say worse in CL) where ` is used instead of quasiquote and , instead of unquote. Surprisingly, in CL
(equal ``3 ''3) => T
-----------------------
Promote Your Functions!
-----------------------
http://kazimirmajorinc.blogspot.com/2008/06/promote-your-functions.html
;---------------------------------------------------------------
; As usually, few definitions I frequently use.
(set 'macro (lambda-macro()(append (lambda-macro) (args))))
(set 'function (macro() (append (lambda) (args))))
(set '-line (dup "-" 64))
(set '--- (function()(println -line)))
(set '§§ (macro(§-argument)
(list '-> §-argument (eval §-argument))))
(set '§ (macro() (doargs(§§-argument)
(println (eval (list '§§ §§-argument))))))
;---------------------------------------------------------------
; I'll try to define some tools for defining of the very simple
; class of the higher order functions, based on the "ordinary"
; functions. For example, for a given function add, I want to
; define addf, which does not sum the numbers, but functions.
;
; But, what does it mean? What is the sum of the functions,
; say, sin and cos? The simplest and in mathematics most
; frequently used definition is that the result is the function
; sin + cos such that
;
; (sin + cos)(x) = sin x + cos x
;
; In Newlisp terms, it is
;
; ((addf 'sin 'cos) x) = (add (sin x) (cos x))
; Furthermore, after I learn how to define addf manually, I want
; to develop tool, i.e function that does the same, so I can simply
; write
; (set 'addf (increase-order 'add))
; I have to write such programs very gradually, starting with
; simple examples, and slowly generalizing. Otherwise, I find
; myself guessing about errors in the code I only partially understand.
; So, let's start with expression (add (sin 3)(cos 3)):
(§ (add (sin 3) (cos 3)))
; RESULT: (-> (add (sin 3) (cos 3)) -0.8488724885)
; Now, an easy part. How function that takes 3 as an argument and
; returns -0.84888... looks like? Obviously,
;
; (lambda(x)(add (sin x) (cos x))).
;
; Or, using previously defined "function:"
(§ ((function(x)(add (sin x) (cos x))) 3))
; RESULT: (-> ((lambda (x) (add (sin x) (cos x))) 3) -0.8488724885)
; As expected, it works.
;---------------------------------------------------------------
; Now, look at the list (add (sin x) (cos x) ....). It appears
; that part can be generated by appending of the list (add) and list
; ((sin x) (cos x) ...). This second can be the result of some
; function that accepts two arguments: list of the function names,
; (or more generally, s-expressions that evaluate to functions) and
; of an argument on which functions will be applied.
; Let's call that function pamq, because it is somehow
; dual to the function map. So, I want
; (pamq (list 'sin 'cos) 'x) => ((sin x) (cos x))
; it is not complete dual. Because in Newlisp, (map 'sin (list 'x 'y))
; does not evaluate to ((sin x) (sin y)); instead, map tries to apply
; sin on x and y, and if these have values, say 1 and 2 respectively,
; it evaluates to
; (0.8414709848 0.9092974268),
(---)
(set 'pamq (function(L a)
(map (function(li)(list li a)) L)))
; Does it work?
(§ (pamq (list 'sin 'cos) 'x))
; It does: (-> (pamq (list 'sin 'cos) 'x) ((sin x) (cos x)))
; However, if I'm already here, I'll also write real pam, to be dual to
; map; and mapq to be dual to pamq, I'll put these functions in
; my library, just in the case I'll need them
; in future.
(---)
(set 'pam (function(L a)
(map (function(fi)(eval (list fi a))) L)))
(set 'mapq (function(f L)
(map (function(li)(list f li)) L)))
(§ (pam (list 'sin 'cos) 3)) ;(-> ... (0.1411200081 -0.9899924966))
(§ (mapq 'sin (list 'x 'y))) ;(-> ... ((sin x) (sin y)))
; They work. Back to the task of writing function addf such that
; (addf f1 ... fn) evaluates to (lambda(x)(add (f1 x)(f2 x)...(fn x))).
(set 'addf (function()
(append '(lambda(x))
(list (append '(add) (pamq (args) 'x))))))
; Does it work?
(---)
(§ (addf 'sin 'cos)) ;(-> ... (lambda (x) (add (sin x) (cos x))))
(§ ((addf 'sin 'cos) 3)) ; (-> ... -0.8488724885)
; It does. The definition of 'addf is rather complicated. It is
; complicated because I must leave the expression (args) unquoted.
; Now, I'll make one generalization further. Sumation of the functions
; have sense for functions that accept more than one argument.
; For example, * and / accept two arguments and they can be added too.
; So, I want function that takes functions f1, f2 ... etc as argument
; and evaluates to
; (lambda()(add (apply f1 (args)) .... (apply fn (args))))
; suddenly, my pretty function pamq is rather useless, and the best thing
; I can do is to write similar, but special function for this purpose:
(set 'pamq-special (function (L)
(map (function(li)(list 'apply li '(args))) L)))
(---)
(§ (pamq-special (list 'sin 'cos)))
; It works: (-> ... ((apply sin (args)) (apply cos (args))))
(set 'addf (function()
(append '(lambda())
(list (append '(add) (pamq-special (args)))))))
(§ (addf 'sin 'cos)) ;(-> ... (lambda () (add (apply sin (args))
; (apply cos (args)))))
(§ ((addf 'sin 'cos) 3)) ; (-> ... -0.8488724885)
; It's even better; pamq-special and addf use fewer symbols.
; Another test: the function +*/ is defined as sum of two
; functions of two arguments, * and /. The result should be
; (+*/ 4 2) = (+ (* 4 2) (/4 2)) = 10.
(---)
(set '+*/ (addf '* '/))
(§ (+*/ 4 2))
; OK, it works. Now, I'm ready for the last and most productive
; generalization - instead of using addf defined "by hand", I'll
; define function "increase-order" that accepts "ordinary" function as
; argument and returns it higher-order version.
;
; For example, "increase-order" should be able to take add as argument,
; and return value of already defined addf,
;
; (function()
; (append '(lambda())
; (list (append '(add) (pamq-special (args)))))))
(set 'increase-order
(function()
(eval (list 'function '()
(list 'append ''(lambda())
(list 'list (list 'append (list 'quote (args))
'(pamq-special (args)))))))))
; Again, it is rather complicated. Not long, but complicated.
; There are lot of "lists" and "eval."; Why they are necessary?
; Because I had to ensure that the first occurence of (args) is free,
; i.e. it is not quoted, and Newlisp has no "quasiquote" yet.
; But it is relatively pretty function; it does not use any local
; variable. One can complain that it requires my user-made
; functions "function" and "pamq-special", but they can be eliminated.
(---)
(§ (increase-order 'add))
; (-> ... (lambda ()
; (append '(lambda ())
; (list (append (quote (add))
; (pamq-special (args)))))) )
; Hm ... it could work
(set 'addf (increase-order 'add))
(set '+f (increase-order '+))
(set 'sin+cos (addf 'sin 'cos))
(set '+*/ (+f '* '/))
(§ (sin+cos 3)) ; (-> (sin+cos 3) -0.8488724885)
(§ (+*/ 4 2)) ; (-> (+*/ 4 2) 10)
; Yap, it does work. But, what is the advantage of defining such
; functions? Shortening of the programs, clarity of the conceptions
; and possibly, easier detection of errors.
;---------------------------------------------------------------
; Example: increase-order is used for definition of reversef function
; that doesn't reverse the lists, but generates the function that
; reverses the lists, beside doing something else.
(---)
(set 'reversef (increase-order 'reverse))
(set 'reversed-map (reversef 'map)) ;
(§ reversed-map)
(§ (reversed-map 'sqrt (list 1 4 9 16)))
; (-> reversed-map (lambda () (reverse (apply map (args)))))
; (-> (reversed-map 'sqrt (list 1 4 9 16)) (4 3 2 1))
; Of course, the same result can be achieved without reversef,
; just it will require seven instead of two tokens and 16 instead of 5
; if we count apostroph and parentheses as well.
--------------------------------
Assignment Macro Beast Unleashed
--------------------------------
http://kazimirmajorinc.blogspot.com/2008/06/assignment-macro-beast-unleashed.html
;===============================================================
;
; C has a lot of handy assignment operators like += and *=.
; Someone might want them in Newlisp - in fact, I've seen some
; already asked for them on Newlisp forum. This article
; is about such operators. Just like usually, you can simply cut
; and past and run the whole code, with comments.
; We have a luck. Equivalent macros can be easily defined in Newlisp.
(set 'setq+ (lambda-macro()
(set (first (args))
(apply + (map eval (args))))))
; TEST:
(setq x 4)
(setq+ x (* 5 5))
(println "Value of x should be 29 and it is actually " x ".")
;===============================================================
;
; Of course, setq+ is only one of many potentially useful similar
; assignement. That justifies the writing of the higher order
; function that accept name of the function (say +) and returns
; appropriate "assignement macro (like set+).
; I'll use "expand" function I learnt these days. With expand,
; I can easily use definition of setq+ in more general form.
; "Expand" can significantly simplify writing of macros.
(set 'hsetq
(lambda-macro()
(let ((operator (first (args))))
(expand '(lambda-macro()
(set (first (args))
(apply operator
(map eval (args)))))
'operator))))