dcsimg
Results 1 to 2 of 2

Thread: Functional Program (a sort of) in M2000

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    May 2014
    Location
    Kallithea Attikis, Greece
    Posts
    948

    Functional Program (a sort of) in M2000

    I make some functions to act like in functional programming.
    (M2000 last revision 55, edition 8)

    Code:
    \\ functional programming
    \\ We can mimic functional programming using stack
    \\ and the call to function where we can use stack for input/output
    \\ We push reference to functions in stack also
    \\ We use a tristate flag to inform for first pass and last pass, for stack preparation
    \\
    function result {   \\ take 1 and give 1
          read tristate
          read &what()
          push tristate
          call what()
          read a
          data a
          if tristate>=0 then push &what()
    }
    function simplelist { 
          drop 1  \\ no need tristate
          if empty then push 0
    }
    function integer {
          read tristate
          if tristate=1 then push 0  \start
            read a : push a+1
           if tristate>=0 then over
    }
    function square_of {
          read tristate
          read &what()
          push tristate
          call what()
          read a
          data a*a
          if tristate>=0 then push &what()
     } 
     function cubic_of {
            read tristate
          read &what()
          push tristate
          call what()
          read a
          data a*a*a
          if tristate>=0 then push &what()
     } 
     function take {
           read  many
           read  &code()
           tristate=1  \\ start
           {
                many--
                if many<1 then tristate=-1
                push tristate   \\ the end message
                call code()
                if tristate>=0 then loop
                tristate=0
          }
    }
    
    \\ this is the program
    \\ 4 actions
    form 60,30
    flush
    \\ take 25 square_of integer
    call  take(25, &square_of(), &integer())
    while not empty {print number,}  
    print
    \\ take 25 cubic_of integer
    call  take(25, &cubic_of(), &integer())
    while not empty {print number,}  
    print
    \\ take 5 cubic_of simplelist 2,8,15,20,12
    call  take(5, &cubic_of(), &simplelist(),2,8,15,20,12)
    while not empty {print number,}  
    print
    \\ take 5 result integer
    call take(5,&result(), &integer())  
    while not empty {print number,}   \\ print 1,2,3,4,5
    print

  2. #2

    Thread Starter
    Fanatic Member
    Join Date
    May 2014
    Location
    Kallithea Attikis, Greece
    Posts
    948

    A second solution

    This is better solution.
    We can use functions or list of functions fot input to Goal module plus (optionaly) a rederection function. So in the second function we can provide another list to apply an operation to anyt combinations from each item in each lit. Without second parameter we get print out (to screen by default) using an internal redirection function.

    Global ThisString$ : Goal "{call integer(25)}" , "{qubic_of &ThisString$}" : Print ThisString$

    We can make lists with expressions with eager or lazy computation.

    a$=list$(10+5, {50+sqrt(50)})
    give a list with two items {=15}, {=50+sqrt(50)} so the second one is the lazy computation.

    All items in the list output from list$() function are function. In M2000 we can define global variables and arrays for temporary use. Using a For this {} block we open a temporary use of definitions, in current namespace. We use this feature for another reason. We can't pass a reference to a defined variable, only when we create one. So if we wish to make new references we have to delete first and re defined next. This can be done with For This { } block.
    References in M2000 are strings, with the proper name to link to original variable or array. But for functions there is no hot link...instead M2000 pass the definition, so a reference to function is a new copy of function, and if this happen to a different module or function from the one where we create original function then we have a function with different namespace. So function reference means a feature to copy function to a new namespace. Because the actual reference is a string we can make functions on the fly and put in stack and then read it a function (but only one reference for a name, unless use the For This {} to delete first define next). A string is stack has to be "{*}" where * is the code. Strings in M2000 can use " " or { }.
    Print "{hello}",{"hello"}
    {hello} "hello"

    push "{read a, b : =a*b}" : for this {read &K() : print K(10,20) }
    push "{read a, b : =a**2+5b-4}" : for this {read &K() : print K(10,20) }

    \\ without for this {} we get an error in Read &K() because k() exist
    \\ in a for this {} any old variable/function/module are untouched.
    push "{read a, b : =a^2+5b-4}" : for this {read &K() : print K(10,20) } \\ ** or ^ for power


    Another point is the calling mechanism in M2000
    1. Calling using current stack of values, return changed stack
    Call anyfunction()
    2 Calling using a new stack for private use. current stack not changed
    Push anyfunction() or a=anyfunction()

    In (1) a non zero return value is an error. So for this variant of calling we use Push to export one or more results
    function alfa { read a, b, c : print a,b*c : push b*c, a}
    Push 10,20 \\ stack has 20,10,....
    call alfa(5)
    5 200
    \\ stack 5, 200,....
    Print alfa(8,5,10)
    8 50 0
    \\ stack didn't change - 0 from alfa() by default return value.
    So when we design a function we have to think how we can call


    push 10,20,5 : call alfa()
    call alfa(), 10,20,5
    call alfa(10,20,5) \\ is the same all of three with variant 1.





    See the examples:

    Code:
    \\ functional programming
    \\ written in M2000
    \\ by George Karras
    \****************** Module Global Pack ******************************************
    \* Read a reference to string, Then Read either a number or a string
    \* Pack this to string
    \* no value return to Stack  
    \**************************************************************************
    Module Global Pack {
                Read &a$
                If isnum Then push trim$(str$(number))
                If a$="" Then { a$="{"+letter$+"}"
                 } else  a$=a$+", {"+letter$+"}" 
          }
    \********************Module Global Unpack********************************
    \* Read a string and Then using like operator (~) do this
    \*  If find pattern "*=*" Then put  { } to make it a nameless Function
    \*  If Not Then insert {= and } and make it a nameless functio too
    \*  Then return result to Stack   (one input, one output)
    \**************************************************************************
    Module Global Unpack { 
          Read b$
          If b$ ~ "*=*" Then {
           b$="{"+b$+"}"
          } else  b$="{= "+b$+"}"
          push b$
    }     
    \**********************Function Global List$******************************
    \* Take a list of parameters and export a formated string
    \* We can put expressions or strings or nameless functions (are strings too)
    \* Without parameters return Empty list
    \* we can put { } for lazy evalutons, or without for eager
    \* we can use global variables, or we can use locals, see examples
    \************************************************************************** 
    Function Global List$ {
          s$=""
          \\  all parameters are in Stack, including references to Function
          If stack.size =0 Then push ""
          for i=1 to stack.size { Pack &s$ }
          =s$
    }
    \**************************** Function List.count************************************ 
    \* We can Read the number of elements in the list
    \* When we call a function without Call (so in an expression) we have New Stack
    \* We use by value pass. We push all to Stack and we get the Stack size
    \************************************************************************************** 
    Function List.count {
          Read a$
          Inline "push "+a$
          =stack.size
    }
    \*******************************Module  Goal****************************************** 
    \* We use it to get results, on lists. It is not a global module
    \* Can take one or two parameters.
    \* One parameter is the a reference to a string that we make it with list$()
    \* Without second parameter we use internal function to display list
    \* Second parameter can be a reference to function, or a nameless function
    \* every element in the list processing with this function
    \* we have to provide proper function to get results in a global string as a list
    \* see examples
    \************************************************************************************** 
    Module Global Goal {
          over : read test$
          if instr(test$,"{")=1 then { 
                Read &a()    \\ function
                stack new {
                a$=""
                call a()
                if stack.size=0 then break
                for i=1 to stack.size {pack &a$}
                }
          } else Read &a$
          if a$="" then exit
          If match("S") Then  { Read  &redirect() } else Function redirect {Read a: print a}
          Stack New {           \\ we work in a new stack, in the exit old stack return
                                        \\ inline run string as code
                Inline "Data "+a$     \\ Send to bottom in stack - like FiFo  \\ Push send to top LiFo
                While Not Empty {
                      For This {      \\ a for something {} has a temporary space for definitions
                            Unpack        \\  for each element in stack we create a pp() function.
                            Read &pp()    \\ we can't assign new reference except if we have a new name
                            push  pp()  \\ we expect always one "solution"
                            call redirect()   
                            \\ now pp() deleted, so next time Read can make the reference
                      }
                }
          }
    
    }
    \********************************Module Global Process******************************* 
    \* Input a list and an opcode as string  (string in M2000 may included in  " " or { })
    \* also read a number. This number is exported by Goal module as result.
    \* Process is usefull because gives a list of function for each element  in Goal's list
    \* We can use one element in Goal times as many in Process as in list.
    \************************************************************************************** 
    Module Global Process {  
          Read mylist$, op$
          Read a    
          Stack New {
                Inline "data "+ mylist$
                Read where$   \\ need something like that &any$ \\ Global any$
                While Not Empty {
                      for this {
                            Unpack
                            Read &bb()
                            Inline " Pack "+where$+", a"+op$+"bb()"                       
                      }
                }
          }
    }
    \************************************************************************************** 
    \* See examples here. Included integer(n) to generate 1..n, and 
    \* cubic_of and square_of  for performing some tasks
    \* Ino one line use: no variables, we give a list (from generator) and we get a list).
    \* Global ThisString$ : Goal "{call integer(25)}"  , "{qubic_of &ThisString$}" : Print ThisString$
    \************************************************************************************** 
    
    form 60,28
    flush
    Print list.count("")  \\ 0
    Global ab=10, bb=30
          a$=List$({bb+=ab : =sqrt(ab)},40,{ab**2+bb-20}, 50,60)
                \\ a$ now is a list of functions.
                \\ without second parameter Goal just Process the functions and display
                Goal &a$    \\ spaces are ignored - so put extra to make code more readable.
    Global sss$
          Goal &a$,  "{Pack &sss$}"  \\ copy results to sss$ (all elements are functions)
                print sss$
    
    Print ab, bb
    
    \\ list x list computation
    Global add$, mul$
    a$=List$(1,2,3)    \\ add each element in a$ to a given list and export to add$
    \\ try to insert new elements or remove some and run this again
    global b=10, a=25
    \\ we use two a here, one is global (inside {q/2+b }) and one is local and is the a$ list item
    Goal &a$  ,  "{Process List$({&add$},{b++: =b},5,{a/2+b},20, a),{+} }"
    print add$     
      \\ multiply each element in a$ to a given list and export to mul$
    Goal &a$  ,  "{Process List$({&mul$},{b++: =b},5,{a/2+b},20),{*} }"
    Print mul$
    
    global Result$, Result1$, Result3$
    zero$=list$(25)
    Goal  &zero$, "{read kl : for i=1 to kl {data i*i : Pack &Result$}}"
    Print Result$
    Goal "{for i=1 to 25 {data i*i}}", "{Pack &Result1$}"
    Print Result1$
    function global integer { read x : while x>0 { push x : x--}}
    module global square_of { Read &S$, x: Pack &S$, x*x}
    module global qubic_of { Read &S$, x: Pack &S$, x*x*x}
    Goal "{call integer(25)}"  , "{square_of &Result3$}"
    Print Result3$
    
    Clear Result3$   \\\ or   Result3$<=0  - we use <= for globals  \\\ or Let Result3$=0 without <=
    Goal "{call integer(25)}"  , "{qubic_of &Result3$}"
    Print Result3$
    print "ok"
    Last edited by georgekar; Sep 29th, 2015 at 03:23 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width