Posted to tcl by mjanssen at Sun Jun 14 15:47:17 GMT 2009view pretty
# FP (http://www.stanford.edu/class/cs242/readings/backus.pdf)[1] # Note that is very easy to add a FP framework in Tcl (it would even be easier if # leading words were autoexpanded # define $name which will be $expanded to body # would be unnecessary if leading words were expanded proc Def {name body} { proc $name x "{*}$body \$x" } # print x proc print {options x} { puts {*}$options $x return $x } # the Backus paper defines integers a objects. # Change unknown to provide this catch {interp hide {} unknown} proc unknown args { set first [lindex $args 0] if {[string is integer $first]} { return $first } else { interp invokehidden {} unknown {*}$args } } # primitives functions # bottom proc bottom {cause} { return -code error -level 1 $cause } # selector, counting starts a 1 proc @ {idx x} { lindex $x $idx-1 } # tail proc tl {x} { lrange $x 1 end } # identity proc id {x} { set x } # equality proc eq {x} { if {[llength $x] != 2} { bottom "eq requires two element sequence" } set y [lindex $x 0] set z [lindex $x 1] expr {$y == $z} } # comparison proc < {x} { if {[llength $x] != 2} { bottom "eq requires two element sequence" } set y [lindex $x 0] set z [lindex $x 1] expr {$y < $z} } proc < {x} { if {[llength $x] != 2} { bottom "eq requires two element sequence" } set y [lindex $x 0] set z [lindex $x 1] expr {$y < $z} } # distribute x(1) to the left of the elements of x(2) proc distl {x} { set res {} set y [lindex $x 0] set zs [lindex $x 1] foreach z $zs { lappend res [list $y $z] } return $res } # distribute x(2) to the right of the elements of x(1) proc distr {x} { set res {} set z [lindex $x 1] set ys [lindex $x 0] foreach y $ys { lappend res [list $y $z] } return $res } # length of x proc length {x} { return [llength $x] } # math ops proc + {x} { if {[llength $x] != 2} { bottom "+ requires two element sequence" } set y [lindex $x 0] set z [lindex $x 1] expr {$y + $z} } proc * {x} { if {[llength $x] != 2} { bottom "* requires two element sequence" } set y [lindex $x 0] set z [lindex $x 1] expr {$y * $z} } proc - {x} { if {[llength $x] != 2} { bottom "- requires two element sequence" } set y [lindex $x 0] set z [lindex $x 1] expr {$y - $z} } proc / {x} { if {[llength $x] != 2} { bottom "/ requires two element sequence" } set y [lindex $x 0] set z [lindex $x 1] expr {$y / $z} } proc apndl {x} { set y [lindex $x 0] set z [lindex $x 1] list $z {*}$y } proc apndr {x} { set y [lindex $x 0] set z [lindex $x 1] list {*}$y $z } # transpose a matrix (a sequence of sequences) proc iota n { set res {} for {set i 0} {$i<$n} {incr i} {lappend res $i} set res } proc trans {x} { set cols [iota [llength [lindex $x 0]]] foreach row $x { foreach element $row col $cols { lappend $col $element } } set res {} foreach col $cols {lappend res [set $col]} set res } # functionals # composition proc o {args} { set x [lindex $args end] set funcs [lrange $args 0 end-1] set res $x foreach f [lreverse $funcs] { set res [{*}$f $res] } return $res } # construction proc {,} {args} { set x [lindex $args end] set funcs [lrange $args 0 end-1] set res {} foreach f $funcs { lappend res [{*}$f $x] } return $res } # insert (aka foldl) proc insert {f x} { set res {} if {[llength $x]==1 } { set res $x } { set res [$f [list [hd $x] [insert $f [tl $x]]]] } return $res } # apply to all (aka map) proc a {f x} { set res {} foreach el $x { lappend res [{*}$f $el] } return $res } # binary to unary proc bu {f x y} { {*}$f [list $x $y] } # conditional execution of $f or $g based on $p:$x proc cond {p f g x} { if {[{*}$p $x]} { set res [{*}$f $x] } else { set res [{*}$g $x] } return $res } # additional functionals not defined in [1] # apply (:) is not available in FP because functions are not objects # we have EIAS so we can add it proc : {x} { set f [lindex $x 0] set x [lindex $x 1] {*}$f $x } catch {interp hide {} split} proc split {c x} { interp invokehidden {} split $x $c } ##################################################################### # examples Def Display {print {}} Def DisplayElements {a Display} Def ex {o Display :} Def hd {@ 1} # innerproduct Def IP {o {insert +} {a *} {trans}} ex {IP {{1 2 3} {6 5 4}}} # factorial Def sub1 {o - {, id 1}} Def eq0 {o eq {, id 0}} Def fact {cond eq0 1 {o * {, id {o fact sub1}}}} ex {fact 12} # mean Def mean {o / {, {insert +} length}} ex {mean {1 2 3 4}} ex {mean {1. 2 3 4}} # contrast to http://wiki.tcl.tk/13125 proc double x {expr {double($x)}} Def sum {insert +} Def mean {o / {, sum {o double length}}} ex {mean {1 2 3 4}} # matrix multiplication Def aaIP {a {a IP}} Def MM {o aaIP {a distl} distr {, {@ 1} {o trans {@ 2}}}} ex {MM {{{1 2} {3 4}} {{5 6} {7 8}}}} # some stuff from the language shootout # Ackerman function Def m {@ 1} Def n {@ 2} Def m-1 {o sub1 m} Def n-1 {o sub1 n} Def m==0 {o eq0 m} Def n==0 {o eq0 n} Def n+1 {o + {, n 1}} Def Ack {cond {m==0} n+1 { cond {n==0} { o Ack {, m-1 1}} {o Ack {, m-1 {o Ack {, m n-1}}}}}} ex {Ack {3 3}} # Fibonacci number Def <2 {o < {, id 2}} Def -2 {o - {, id 2}} Def -1 {o - {, id 1}} Def Fib {cond <2 1 {o + {, {o Fib -2} {o Fib -1}}}} ex {Fib 16} # Tak function Def x {@ 1} Def y {@ 2} Def z {@ 3} Def y<x {o < {, y x}} Def x-1 {o sub1 x} Def y-1 {o sub1 y} Def z-1 {o sub1 z} Def Tak1 {o Tak {, x-1 y z}} Def Tak2 {o Tak {, y-1 z x}} Def Tak3 {o Tak {, z-1 x y}} Def Tak {cond y<x {o Tak {, Tak1 Tak2 Tak3}} z} ex {Tak {3 2 1}} Def DisplayShoutout {o Display {, {@ 1} {o : tl}}} Def Bench {o {print -nonewline} : {, time id}} Bench { DisplayShoutout {Ack(3,3): Ack {3 3}} # disabled because takes ages (2 minutes on my system) # DisplayShoutout {Fib(30.0): Fib 30.0} DisplayShoutout {Tak(6,4,2): Tak {6 4 2}} DisplayShoutout {Fib(3): Fib 3} DisplayShoutout {Tak(3.0,2.0,1.0): Tak {3.0 2.0 1.0}} } Display { microseconds per iteration} # read a file Def readfile {o {split \n} {@ 1} {, read close} open} Def displayfile {o DisplayElements readfile} displayfile c:/boot.ini # append two lists Def ynil {o eq0 {o length {@ 2}}} Def y {@ 2} Def hy {o hd y} Def ty {o tl y} Def ahead {o apndr {, x {o hd y}}} Def append {cond ynil x {o append {, ahead ty}}} ex {append {{1 2 3} {4 5 6}}} set a {}