lambdaway
::
eric_dobbs
1
|
list
|
login
|
load
|
|
_h2 eric_dobbs | [[eric_dobbs2]] | [[eric_dobbs3]] _p A mail from Eric Dobbs on 2021/12/29 08:44 {prewrap Hello Alain. I've enjoyed following some of these conversations you've had with Ward and Thomson. Tonight I had a difficult time porting some LOGO code to lambdatalk. I think I'm missing something basic. Some years ago I volunteered with a summer programming camp and helped an advanced 5th grader learn some fun things with Microworlds Logo. Short story is that we started with some found code for the Von Koch snowflake. We generalized the code to remove some repetition. That allowed us to discover similarity to the Peano curve. Longer story is over here: [[http://dobbse.net/thinair/2008/12/logo-fractals-recursion.html|http://dobbse.net/thinair/2008/12/logo-fractals-recursion.html]] I was not able to get DrawFractalLine ported to lambdatalk. I did find an implementation of logo where I could share a running variant of the code "Sam" and I worked on. Here's the logo interpreter: [[https://www.calormen.com/jslogo/|https://www.calormen.com/jslogo/]] Should be able to just copy & paste the following code to see these visually. {prewrap to DrawFractalLine :commands :level :length ( define "walk [ [ command ] [ DrawFractalLine :commands (sum -1 :level) (quotient :length 3.0) if not empty? :command [ run :command ] ] ] ) ifelse :level < 1 [ forward :length ] [ foreach "walk :commands ] end to VonKoch :level :length DrawFractalLine [ [ left 60 ] [ right 120 ] [ left 60 ] [ ] ] :level :length end to Peano :level :length DrawFractalLine [ [ left 90 ] [ right 90 ] [ right 90 ] [ right 90 ] [ left 90 ] [ left 90 ] [ left 90 ] [ right 90 ] [ ] ] :level :length end to SamCurve :level :length DrawFractalLine [ [ left 90 ] [ right 90 ] [ right 90 ] [ ] [ right 90 ] [ right 90 ] [ right 90 ] [ forward (2 * :length / 3) ] ] :level :length end clearscreen rt 90 penup setpos [ 0 175 ] pendown VonKoch 3 200 penup setpos [ 0 50] pendown Peano 3 200 penup setpos [ 0 -150] pendown SamCurve 3 120 } It seems like this should all code up pretty nicely in lambdatalk too, but I couldn't figure out how to pass in a list of commands and get them applied over a list in the recursion. I tried using {S.map fn list} in various ways but couldn't quite get it working. Take care. -Eric } _p Here is a translation from LOGO to lambdatalk. _h2 1) the simplest version {pre '{def koch {lambda {:level :length} {if {< :level 1} then M:length else {koch {- :level 1} {/ :length 3}} T-60 {koch {- :level 1} {/ :length 3}} T120 {koch {- :level 1} {/ :length 3}} T-60 {koch {- :level 1} {/ :length 3}} }}} -> {def koch {lambda {:level :length} {if {< :level 1} then M:length else {koch {- :level 1} {/ :length 3}} T-60 {koch {- :level 1} {/ :length 3}} T120 {koch {- :level 1} {/ :length 3}} T-60 {koch {- :level 1} {/ :length 3}} }}} '{def peano {lambda {:level :length} {if {< :level 1} then M:length else {peano {- :level 1} {/ :length 3}} T-90 {peano {- :level 1} {/ :length 3}} T90 {peano {- :level 1} {/ :length 3}} T90 {peano {- :level 1} {/ :length 3}} T90 {peano {- :level 1} {/ :length 3}} T-90 {peano {- :level 1} {/ :length 3}} T-90 {peano {- :level 1} {/ :length 3}} T-90 {peano {- :level 1} {/ :length 3}} T90 {peano {- :level 1} {/ :length 3}} }}} -> {def peano {lambda {:level :length} {if {< :level 1} then M:length else {peano {- :level 1} {/ :length 3}} T-90 {peano {- :level 1} {/ :length 3}} T90 {peano {- :level 1} {/ :length 3}} T90 {peano {- :level 1} {/ :length 3}} T90 {peano {- :level 1} {/ :length 3}} T-90 {peano {- :level 1} {/ :length 3}} T-90 {peano {- :level 1} {/ :length 3}} T-90 {peano {- :level 1} {/ :length 3}} T90 {peano {- :level 1} {/ :length 3}} }}} '{def sam {lambda {:level :length} {if {< :level 1} then M:length else {sam {- :level 1} {/ :length 3}} T-90 {sam {- :level 1} {/ :length 3}} T90 {sam {- :level 1} {/ :length 3}} T90 {sam {- :level 1} {/ :length 3}} T0 {sam {- :level 1} {/ :length 3}} T90 {sam {- :level 1} {/ :length 3}} T90 {sam {- :level 1} {/ :length 3}} T90 {sam {- :level 1} {/ :length 3}} M{* 2 {/ :length 3}} }}} -> {def sam {lambda {:level :length} {if {< :level 1} then M:length else {sam {- :level 1} {/ :length 3}} T-90 {sam {- :level 1} {/ :length 3}} T90 {sam {- :level 1} {/ :length 3}} T90 {sam {- :level 1} {/ :length 3}} T0 {sam {- :level 1} {/ :length 3}} T90 {sam {- :level 1} {/ :length 3}} T90 {sam {- :level 1} {/ :length 3}} T90 {sam {- :level 1} {/ :length 3}} M{* 2 {/ :length 3}} }}} } _p It's easy to understand but there are lots of repetitions which should be replaced by a loop. See section 2) _p Drawings are called like this: {pre '{svg {@ width="580" height="580" style="box-shadow:0 0 8px #000;"} {polyline {@ points="{turtle 100 100 0 {koch 3 300}}" stroke="#f00" fill="transparent"}} {polyline {@ points="{turtle 280 250 0 {peano 1 300}}" stroke="#888" fill="transparent" stroke-width="5"}} {polyline {@ points="{turtle 280 250 0 {peano 3 300}}" stroke="#0f0" fill="transparent"}} {polyline {@ points="{turtle 400 10 0 {sam 1 200}}" stroke="#888" fill="transparent" stroke-width="5"}} {polyline {@ points="{turtle 400 10 0 {sam 3 200}}" stroke="#00f" fill="transparent"}} } } _p Note that such a code is the immediate translation of standard HTML/CSS/SVG syntaxes. Details of {b svg, polyline, stroke, ...} can be found anywhere on the net. For instance {pre '{polyline {@ points="{turtle 280 250 0 {peano 3 300}}" stroke="#0f0" fill="transparent"}} } _p could be written {pre <{span}polyline points="'{turtle 280 250 0 {peano 3 300}}" stroke="#0f0" fill="transparent" /> } _p It's a matter of choice. The result is below {svg {@ width="580" height="580" style="box-shadow:0 0 8px #000;"} {polyline {@ points="{turtle 100 100 0 {koch 1 300}}" stroke="#ccc" fill="transparent" stroke-width="5"}} {polyline {@ points="{turtle 100 100 0 {koch 3 300}}" stroke="#f00" fill="transparent"}} {polyline {@ points="{turtle 280 250 0 {peano 1 300}}" stroke="#ccc" fill="transparent" stroke-width="5"}} {polyline {@ points="{turtle 280 250 0 {peano 3 300}}" stroke="#0f0" fill="transparent"}} {polyline {@ points="{turtle 400 10 0 {sam 1 200}}" stroke="#ccc" fill="transparent" stroke-width="5"}} {polyline {@ points="{turtle 400 10 0 {sam 3 200}}" stroke="#00f" fill="transparent"}} } _p Some more curves (and better explanations) can be seen in [[koch]], [[hilbert]], [[peano]], [[sierpinsky]], [[fern]], [[dragon]], [[fractal_tree]], [[stars]], ... _h2 2) removing repetitions _p This is the {b DrawFractalLine} Logo function in [[http://dobbse.net/thinair|http://dobbse.net/thinair/2008/12/logo-fractals-recursion.html]] {pre to DrawFractalLine :commands :level :length ( define "walk [ [ command ] [ DrawFractalLine :commands (sum -1 :level) (quotient :length 3.0) if not empty? :command [ run :command ] ] ] ) ifelse :level < 1 [ forward :length ] [ foreach "walk :commands ] end } _p This recursive function contains a loop, {b foreach}, and the goal is to put in such a loop the repetitions found in lambdatalk functions above and to hide recursive details. _h3 1) defining a generic function for a family of fractals {pre '{def fractal {def fractal.repeat {lambda {:level :length :curve :arr} {if {A.empty? :arr} then else {fractal :level :length :curve} {A.first :arr} {fractal.repeat :level :length :curve {A.rest :arr}} }}} {lambda {:level :length :curve} {if {< :level 1} then M:length else {fractal.repeat {- :level 1} {/ :length 3} :curve {:curve :length}} }}} -> {def fractal {def fractal.repeat {lambda {:level :length :curve :arr} {if {A.empty? :arr} then else {fractal :level :length :curve} {A.first :arr} {fractal.repeat :level :length :curve {A.rest :arr}} }}} {lambda {:level :length :curve} {if {< :level 1} then M:length else {fractal.repeat {- :level 1} {/ :length 3} :curve {:curve :length}} }}} } _p We can understand that the line {pre '{fractal :level :length :curve} '{A.first :arr} } _p with {pre :level = '{- :level 1} :length = '{/ :length 3} :curve = koch :arr = [T-60,T120,T-60,T0] } _p generates the following four lines {pre °° {koch {- :level 1} {/ :length 3}} T-60 {koch {- :level 1} {/ :length 3}} T120 {koch {- :level 1} {/ :length 3}} T-60 {koch {- :level 1} {/ :length 3}} °°} _p in the {b koch} function shown in the first section. _p See pages [[lambda]], [[coding]], [[oops]], [[maxwell_equations]] for detailed explanations on lambdas. _h3 2) defining some fractals {pre '{def KOCH {A.new T-60 T120 T-60 T0}} -> {def KOCH {A.new T-60 T120 T-60 T0}} '{def PEANO {A.new T-90 T90 T90 T90 T-90 T-90 T-90 T90 T0}} -> {def PEANO {A.new T-90 T90 T90 T90 T-90 T-90 T-90 T90 T0}} '{def SAM {lambda {:length} {A.new T90 T-90 T-90 T0 T-90 T-90 T-90 M{* 2 {/ :length 3}}}}} -> {def SAM {lambda {:length} {A.new T90 T-90 T-90 T0 T-90 T-90 T-90 M{* 2 {/ :length 3}}}}} '{def VKZIG {A.new T-30 T120 T-120 T30 T0}} -> {def VKZIG {A.new T-30 T120 T-120 T30 T0}} } _p See page [[WAPL]] for explanations about arrays and other data structures. An alternative to arrays could be to use {b sequences} simplifying the above definitions, for example {b '{def VKZIG T-30 T120 T-120 T30 T0}} _h3 3) drawing fractals {pre '{svg {@ width="580" height="580" style="box-shadow:0 0 8px #000;"} {polyline {@ points="{turtle 100 10 0 {fractal 1 300 KOCH}}" stroke="#888" fill="transparent" stroke-width="3"}} {polyline {@ points="{turtle 100 10 0 {fractal 3 300 KOCH}}" stroke="#f00" fill="transparent" stroke-width="1"}} {polyline {@ points="{turtle 250 250 0 {fractal 1 300 PEANO}}" stroke="#888" fill="transparent" stroke-width="3"}} {polyline {@ points="{turtle 250 250 0 {fractal 3 300 PEANO}}" stroke="#0f0" fill="transparent" stroke-width="1"}} {polyline {@ points="{turtle 200 160 90 {fractal 1 200 SAM}}" stroke="#888" fill="transparent" stroke-width="3"}} {polyline {@ points="{turtle 200 160 90 {fractal 3 200 SAM}}" stroke="#00f" fill="transparent" stroke-width="1"}} {polyline {@ points="{turtle 20 20 45 {fractal 4 300 VKZIG}}" stroke="#000" fill="transparent" stroke-width="2"}} } } _h3 4) result {svg {@ width="580" height="580" style="box-shadow:0 0 8px #000;"} {polyline {@ points="{turtle 100 10 0 {fractal 1 300 KOCH}}" stroke="#888" fill="transparent" stroke-width="3"}} {polyline {@ points="{turtle 100 10 0 {fractal 3 300 KOCH}}" stroke="#f00" fill="transparent" stroke-width="1"}} {polyline {@ points="{turtle 250 250 0 {fractal 1 300 PEANO}}" stroke="#888" fill="transparent" stroke-width="3"}} {polyline {@ points="{turtle 250 250 0 {fractal 3 300 PEANO}}" stroke="#0f0" fill="transparent" stroke-width="1"}} {polyline {@ points="{turtle 200 160 90 {fractal 1 200 SAM}}" stroke="#888" fill="transparent" stroke-width="3"}} {polyline {@ points="{turtle 200 160 90 {fractal 3 200 SAM}}" stroke="#00f" fill="transparent" stroke-width="1"}} {polyline {@ points="{turtle 20 20 45 {fractal 4 300 VKZIG}}" stroke="#000" fill="transparent" stroke-width="2"}} } _h2 conclusion _p The {b fractal.repeat} recursive function could be replaced by an iterative version using the {b '{S.map function a sequence of words}} lambdatalk loop structure: {pre '{def fractal.repeat {lambda {:level :length :curve :arr} {S.map {{lambda {:level :length :curve :arr :i} {fractal :level :length :curve} {A.get :i :arr} } :level :length :curve :arr} {S.serie 0 {- {A.length :arr} 1}} }}} } _p You can try it, it works fine, but I think that the recursive version makes code more consistent and easier to understand. _p See [[eric_dobbs2]] for another version. Maybe the best. _p Your opinion is welcome. _p {i Alain Marty | 2021/12/31 - 2022/01/01} {style pre { box-shadow:0 0 8px #000; padding:10px; } }
lambdaway v.20211111