Funk2 Documentation: How to Program in Funk2

Funk2 Documentation: How to Program in Funk2



Overview


    
Funk2 Home...
Supported systems
Basic programming examples
Example of defining and using a frame type
Causal reflective programming
Graph programming examples


Developer Support and Mailing Lists


    

Because Funk2 is currently a very active research project, these documentation pages will not be able to explain the cutting edge features of the language and theory of causal reflection or reflective programming. For the time being, please feel free to email the author, Bo Morgan <bo@mit.edu>, if you have questions or bugs to report. There are publications about the intended uses for Funk2 here: Funk2 Home.



Supported systems


    

Funk2 currently compiles on 32-bit and 64-bit Linux operating systems. 64-bit pointers are recommended because of the amount of memory needed for the reflective capabilities; a 32-bit machine is currently only able to index a few gigabytes of memory.



Basic Programming Examples


    

Here is one straightforward way to write a "Hello world!" program in the Funk2 language:


    in--> [print 'Hello world!']
'Hello world!'
out-> 
'Hello world!'


Here is another more advanced way to holla your planet:


    in--> [let [[planet 'Earth']] [format stdout 'Hello ' planet '!']]Hello Earth!
out-> 
[]


The apropos funktion provides a helpful text search that looks through the local and global environment for funks or metros that have documentation that matches the search string. This feature does not currently search through object type slots, which can be browsed using the lookup_type funktion discuss further below. For now, if you are looking for a sort funktion:


    read> [apropos 'sort']
out-> 
[frame
  
:funk_variable primfunk:array__quicksort   [cfunk :name primfunk:array__quicksort :args [this comparison_funk] :is_funktional [] :documentation 'sort an array of elements in place by user-provided comparison_funk.']
  
:funk_variable primfunk:array__sort        [cfunk :name primfunk:array__sort :args [this comparison_funk] :is_funktional [] :documentation 'sort an array of elements in place by user-provided comparison_funk.']
  
:funk_variable primfunk:conslist__sort     [cfunk :name primfunk:conslist__sort :args [this comparison_funk] :is_funktional [] :documentation 'returns a new conslist that is this conslist sorted by user-provided comparison_funk.']
  
:funk_variable primfunk:sort_integer_array [cfunk :name primfunk:sort_integer_array :args [this] :is_funktional [] :documentation 'sort an array of integers in place.']
  
:funk_variable conslist-sort               [cfunk :name primfunk:conslist__sort :args [this comparison_funk] :is_funktional [] :documentation 'returns a new conslist that is this conslist sorted by user-provided comparison_funk.']
  
:funk_variable array-sort                  [cfunk :name primfunk:array__sort :args [this comparison_funk] :is_funktional [] :documentation 'sort an array of elements in place by user-provided comparison_funk.']
  
:funk_variable array-quicksort             [cfunk :name primfunk:array__quicksort :args [this comparison_funk] :is_funktional [] :documentation 'sort an array of elements in place by user-provided comparison_funk.']
  
:funk_variable sort_integer_array          [cfunk :name primfunk:sort_integer_array :args [this] :is_funktional [] :documentation 'sort an array of integers in place.']]


Here is how to define and subsequently call a funktion:


    in--> [defunk say-hi [x] [format stdout 'Why, hello there ' x '.  It is really great to see you.']]
defunk
say-hi [x]
out-> 
[]
    in--> [say-hi 'Marvin']
Why, hello there Marvin. It is really great to see you.
out-> 
[]


Here is how to loop over a list of values:


    in--> [mapc [funk [x] [print x]] [list 1 2 3 #xff 'dog' `[2 3]]]
1
2
3
#xff
'dog'
[2 3]
out-> 
[]


Here is how to call our funktion above in a parallel thread:


    in--> [prog [thread &say-hi [list 'Gerry']] []]
Why, hello there
out-> Gerry. It is really great to see you.
[]


Here is how to serially filter every element in a list:


    in--> [mapcar [funk [x] [+ x 10]] [list 1 2 3 4 5]]
out-> 
[11 12 13 14 15]


Here is how to concurrently filter every element in a list:


    in--> [parcar [funk [x] [+ x 10]] [list 1 2 3 4 5]]
out-> 
[11 12 13 14 15]




Frame Definition Examples


    

Here is one straightforward way to create a new type of frame:


    read> [deframe dog [frame] [color weight legs]]
[deframe dog [frame] [color weight legs]]
out-> 
[]


We can create a new dog frame like this:


    in--> [new dog]
out-> 
[dog :type dog :legs [] :weight [] :color []]


We can put a new dog frame in a global variable like this:


    in--> [globalize the-dog [new dog]]
out-> 
[]


We can set the dog's color to black like this:


    in--> [set the-dog color `black]
out-> 
[]


We can see our globalized dog frame like this:


    in--> the-dog
out-> 
[dog :type dog :legs [] :weight [] :color black]


We can get the dog's color like this:


    in--> [get the-dog color]
out-> 
black


We can ask for brief documentation for any object like this:


    read> [doc the-dog]
[dog

  [dog legs []]
    - returns nothing.

  [dog weight []]
    - returns nothing.

  [dog color []]
    - returns a symbol (black).]
out-> 
[]


We can see our new frame type like this:


    in--> [lookup_type `dog]
out-> 
[primobject_type
  
:get legs    [funk :name legs :args [this] :is_funktional [] :documentation []]
  
:get weight  [funk :name weight :args [this] :is_funktional [] :documentation []]
  
:get color   [funk :name color :args [this] :is_funktional [] :documentation []]
  
:set legs    [funk :name legs :args [this value] :is_funktional [] :documentation []]
  
:set weight  [funk :name weight :args [this value] :is_funktional [] :documentation []]
  
:set color   [funk :name color :args [this value] :is_funktional [] :documentation []]
  
:variable parents []
  
:variable type    primobject_type
  
:execute new     [funk :name new :args [] :is_funktional [] :documentation []]
  
:execute is_type [funk :name is_type :args [exp] :is_funktional [] :documentation []]]

Here is how to define and subsequently call a funktion:


    in--> [defunk say-hi [x] [format stdout 'Why, hello there ' x '.  It is really great to see you.']]
defunk
say-hi [x]
out-> 
[]
    in--> [say-hi 'Marvin']
Why, hello there Marvin. It is really great to see you.
out-> 
[]




Examples of causal reflective programming


    

Define a property in the current causal frame:


    read> [cause-define username 'Bo Morgan']
out-> 
[]

Causal frame definitions are accessed if there is not a local environmental definition:


    read> username
out-> 
'Bo Morgan'

The shelter command allocates a new parallel fiber with a new cause object. The shelter command takes a list of commands that are executed in sequence. If a bug is encountered, the shelter command returns the symbol sheltered, or otherwise, the normal return value is returned. Following are some examples of how the shelter command may be used:


    read> [cause-define username 'Bo Morgan']
out-> 
[]
read> 
[shelter username]
out-> 
'Bo Morgan'

The shelter command can be used for its new cause frame. Defining new slot values in the new cause frame does not affect the original cause frame:


    read> [shelter [cause-define username 'Muddy Carol'] username]
out-> 
'Muddy Carol'
read> 
username
out-> 
'Bo Morgan'

While the use of the cause frame may not seem to give us much advantage over using normal environment variables, here is an example of how cause frames are different and useful:


    read> [cause-define username 'Bo Morgan']
out-> 
[]
read> 
[defunk say-hello [] [format stdout '\nHello, ' username ', welcome to Funk2.']]
[defunk say-hello []]
out-> 
[]
read> 
[say-hello]
Hello, Bo Morgan, welcome to Funk2.
out-> 
[]
read> 
[shelter [cause-define username 'Muddy Carol'] [say-hello]]
Hello, Muddy Carol, welcome to Funk2.
out-> 
[]
read> 
[shelter [cause-define username 'Carol\'s Mother'] [say-hello]]
Hello, Carol's Mother, welcome to Funk2.
out-> 
[]
read> 
[say-hello]
Hello, Bo Morgan, welcome to Funk2.
out-> 
[]

The shelter command may be used to guard against bugs that would otherwise stop the currently executing fiber:


    read> [shelter [print hello]]
out-> 
sheltered


As an introduction to basic event tracing, let us start with an example of the funktracer command. The funktracer command executes a block of code every time a funk bytecode is executed. A few local environment variables are defined to describe the funktion call, including the funk and args variables. In our example below, the test-funktracer metro takes a block of code and prints the funktion name and a short list of arguments for every funktion that is called within that block.


    read> [defmetro test-funktracer [:rest codes] `[shelter [funktracer [print [list `arg-num: [length args] [get funk name]]]] @codes]]
[defmetro test-funktracer [:rest codes]]
out-> 
[]
read> 
[test-funktracer [print 'hello']]
[arg-num: 1 print]
[arg-num: 2 format]
[arg-num: 1 primfunk:null]
[arg-num: 7 primfunk:make_funk]
[arg-num: 2 mapc]
[arg-num: 2 object-get]
[arg-num: 3 primfunk:object__slot__type_funk]
[arg-num: 2 primfunk:cons__new]
[arg-num: 1 primfunk:cons__car]
[arg-num: 2 primfunk:cons__new]
[arg-num: 1 funk]
[arg-num: 2 primfunk:exp__format]
[arg-num: 2 object-get]
[arg-num: 3 primfunk:object__slot__type_funk]
[arg-num: 2 primfunk:cons__new]
[arg-num: 1 primfunk:cons__cdr]
[arg-num: 1 primfunk:exp__print]
'hello'
out-> 
'hello'


Here is an example of how to remember the value of array slots at previous times. Since arrays are the basic memory type in Funk2, almost all objects can be traced using this array-based memory feature:


    read> [globalize a [new array 10]]
out-> 
[]
read> 
a
out-> 
([] [] [] [] [] [] [] [] [] [])
read> 
[set a elt-tracing_on 0 t]
out-> 
[]
read> 
[set a elt 0 10]
out-> 
[]
read> 
[set a elt 0 20]
out-> 
[]
read> 
[get a elt 0]
out-> 
20
read> 
[get a elt-trace 0]
out-> 
{10 *- 20}
read> 
[get [get a elt-trace 0] prev]
out-> 
{10 20}
read> 
[get [get [get a elt-trace 0] prev] creation_time]
out-> 
[time :days 20 :hours 13 :months 4 :seconds 58 :nanoseconds 775979000 :years 2010 :nanoseconds_since_1970 1271784718775979000 :minutes 31]




Graph Programming Examples


    

Graphs with labeled edges and nodes are useful ways of thinking about many computer science ideas. For example, the following objects can be easily converted to and from a graph representation: (1) relational databases, (2) programming language memory objects, (3) causal traces and other procedural relationships, (4) narratives and stories, (5) frame-based objects, (6) social networks, etc. The Funk2 pattern matching is based on recognizing large and exact patterns in graph structures.


    read> [deframe dog [frame] [legs weight color]]
[deframe dog [frame] [legs weight color]]
out-> 
[]
read> 
[globalize rufus [new dog]]
out-> 
[]
read> 
[get rufus as-graph]
out-> 
[graph
  
:root_node [graph_node :label [dog :type dog :legs [] :weight [] :color []]]
  
:nodes     [[graph_node :label [dog :type dog :legs [] :weight [] :color []]] [graph_node :label dog] [graph_node :label []]]
  
:edges     [[graph_edge :label type :left_node [graph_node :label [dog :type dog :legs [] :weight [] :color []]] :right_node [graph_node :label dog]]
              
[graph_edge :label color :left_node [graph_node :label [dog :type dog :legs [] :weight [] :color []]] :right_node [graph_node :label []]]
              
[graph_edge :label weight :left_node [graph_node :label [dog :type dog :legs [] :weight [] :color []]] :right_node [graph_node :label []]]
              
[graph_edge :label legs :left_node [graph_node :label [dog :type dog :legs [] :weight [] :color []]] :right_node [graph_node :label []]]]]
read> 
[have rufus gview]
out-> 
[]
    


Graphs can also contain variables at nodes and edges. Here, we create a graph from a simple dog frame as in the last example, but we also create another variable graph from this initial graph structure that we store in the rufus-variable_graph global variable. Pay special attention to the very last command, which demonstrates how variable graphs can be matched against object graphs, which returns a hash table of variable bindings. This type of graph matching will be the basis for reflective pattern recognition for building the larger critic-selector architecture within Funk2.


    read> [deframe dog [frame] [legs weight color]]
[deframe dog [frame] [legs weight color]]
out-> 
[]
read> 
[globalize rufus [new dog]]
out-> 
[]
read> 
[set rufus legs 4]
out-> 
[]
read> 
[set rufus weight `heavy]
out-> 
[]
read> 
[set rufus color `brown]
out-> 
[]
read> 
[get rufus as-graph]
out-> 
[graph
  
:root_node [graph_node :label [dog :type dog :legs 4 :weight heavy :color brown]]
  
:nodes     [[graph_node :label [dog :type dog :legs 4 :weight heavy :color brown]] [graph_node :label 4] [graph_node :label dog] [graph_node :label heavy] [graph_node :label brown]]
  
:edges     [[graph_edge :label legs :left_node [graph_node :label [dog :type dog :legs 4 :weight heavy :color brown]] :right_node [graph_node :label 4]]
              
[graph_edge :label type :left_node [graph_node :label [dog :type dog :legs 4 :weight heavy :color brown]] :right_node [graph_node :label dog]]
              
[graph_edge :label weight :left_node [graph_node :label [dog :type dog :legs 4 :weight heavy :color brown]] :right_node [graph_node :label heavy]]
              
[graph_edge :label color :left_node [graph_node :label [dog :type dog :legs 4 :weight heavy :color brown]] :right_node [graph_node :label brown]]]]
read> 
[have rufus gview]
out-> 
[]
    
    read> [globalize rufus-variable_graph [get rufus as-graph]]
out-> 
[]
read> 
[have rufus-variable_graph make_node_variable rufus `x]
out-> 
[graph_variable :name x]
read> 
[have rufus-variable_graph make_node_variable 4 `leg_count]
out-> 
[graph_variable :name leg_count]
read> 
[have rufus-variable_graph make_node_variable `heavy `how_heavy]
out-> 
[graph_variable :name how_heavy]
read> 
[have rufus-variable_graph make_edge_variable `color [new graph_variable `x] `brown `brown_property]
out-> 
[graph_variable :name brown_property]
read> 
rufus-variable_graph
out-> 
[graph
  
:variables [[graph_variable :name x] [graph_variable :name leg_count] [graph_variable :name how_heavy] [graph_variable :name brown_property]]
  
:root_node [graph_node :label [graph_variable :name x]]
  
:nodes     [[graph_node :label dog] [graph_node :label brown] [graph_node :label [graph_variable :name x]] [graph_node :label [graph_variable :name leg_count]] [graph_node :label [graph_variable :name how_heavy]]]
  
:edges     [[graph_edge :label type :left_node [graph_node :label [graph_variable :name x]] :right_node [graph_node :label dog]]
              
[graph_edge :label [graph_variable :name brown_property] :left_node [graph_node :label [graph_variable :name x]] :right_node [graph_node :label brown]]
              
[graph_edge :label legs :left_node [graph_node :label [graph_variable :name x]] :right_node [graph_node :label [graph_variable :name leg_count]]]
              
[graph_edge :label weight :left_node [graph_node :label [graph_variable :name x]] :right_node [graph_node :label [graph_variable :name how_heavy]]]]]
read> 
[have rufus-variable_graph gview]
out-> 
[]
    
    read> [get [get rufus as-graph] contains_match_with_bindings rufus-variable_graph []]
out-> 
[ptypehash :key_count 4 :is_empty [] :write_mutex [mutex :is_locked []] :slot_names [leg_count brown_property how_heavy x] :bin_array ([[x[dog :type dog :legs 4 :weight heavy :color brown]] [how_heavyheavy] [brown_propertycolor]
               
[leg_count4]] [] [] [] [] [] [] [] [] [] [] [] [] [] [] []) :bin_num_power 4]




λ

Blue%20Ribbon%20Online%20Free%20Speech%20Campaign