Closures can also write? Realization of ideas to talk about children's programming tools

  Copyright Notice: This article blogger windows (Colin Cai) original, welcome to reprint. To repost, must indicate the original URL 

  http://www.cnblogs.com/Colin-Cai/p/11601046.html 

  Author: windows 

  QQ / micro letter: 6,679,072 

  E-mail: [email protected]

  Strange code  

 

  

  Look at this code, obviously, it is less than 100 include all primes. We started a program like this written many from the school program.

  A closer look, this "language" seems a bit like we learned other languages, but it does not seem to have seen, there is a little bit weird syntax? !

  

 

  Oh! See, it turned out to be a period of Python !

 

  

  Results of the above code is

  2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97

 

  Think again, this procedure itself is composed of a bunch of functions, all Python function, and all parameters as a function of the run, even this call Parameters of execution. Good weird code! If you think about how to achieve this, for fear it was a bit puzzled.

  

  Process-oriented programming blocks

  

  Children's programming is currently very popular, there are many platforms the world face. The most famous of Scratch, a lot of other children's education platform mostly imitate Scratch ideas.

  

  The above procedure is to generate Scratch mass numbers less than 100, the code we pile roll, not seen even from Scratch, the program will soon discover such blocks above and our language C, Python and other common process-oriented look not a big difference. So, we will soon be using Scratch programming.

  Scrach abstract variables, various arithmetic operations, in addition to the abstract order (command type) is used procedural programming cycle, the conditional branch; Scratch even blocks can also be made to simulate the function of the significance of which to some extent, but blocks You can also recursively; but did not break under Scratch, continue, which makes the program more difficult at a certain extent made up of some. In addition, Scratch and even simulate the message (or signal) trigger such an abstract, the purpose may be to make the program more interesting.

  

  In theory, of course, it can also support programming blocks break, continue, and even can goto.

 

  The most common implementation 

 

  This article does not intend to spend too much space to describe front-end design, albeit a very complex topic. But ideas can design brief speech.

  First of all, we are modeling for each building block, either Python or JavaScript, we can use the class to describe. A building block may be implemented in advance base class properties in the building block may have a size, image information, etc., with a loading method may comprise the image. Each of the particular blocks may be inherited from the base class, of course, also be coupled in succession a layer, such as a class we divided to blocks, such as computing-based, structural class operation, data type, output type, input class ...... building blocks may contain other class of building objects, such as for the operation, it may be even more involved in the other two building blocks of the building blocks. Further, each of the blocks may have a resize or reshape a method, because the shape of the building blocks may be associated with other objects it contains. Of course, such an approach will have to move as needed.

  Secondly, we want to present all the building blocks modeling can be abstracted block (to represent the building blocks for a spell of procedures) and block_list (used to represent all of the block) such classes. block also has split / joint methods for block division, stitching.

  Mouse drag blocks, the above operations may correspond to various objects.

  block_list recorded in all the building blocks, as well as the connection between building blocks and bricks, in fact, these relationships to language compilation, interpretation, it is the first step parser hope the results obtained. Now, although this information is not obtained by the compiler, but to get through the front end of the operation, but the information is complete, you can use this connection direct step by step to get the final result. This approach should be the most normal way.

 

  Use development language

  

  Thus, the simplest implementation may be mapped into individual block currently in a programming language, a programming language then eval function is achieved. Many languages ​​have eval function, so this is hardly a problem.

  For example, suppose we Scratch is written in Python, Scratch program can write the prime building blocks one by one to translate, the following Python code:

var["i"] = 2
while not (var["i"]>10):
    var["k"] =  sqrt(var["i"])
    var["j"] = 2
    while not ((var["i"]>var["j"]) or ((var["i"]%var["j"])==0)):
        var["j"] += 1
    if (var["i"]>var["k"]):
        say(str(var["i"])+"是质数", 1)
    var["i"] += 1

 

  And then to realize the function of the implementation in Python, here say such a function.

  Or more to achieve a more straightforward, in fact, does the world face is commercial software to do so. In particular, some children's online education program, students are expected transition from programming to building specific computer language (general or Python, JavaScript) learning, will give a correspondence between the concrete blocks and computer programming language, for education, which should It is a very good idea. But this also has some problems, because it corresponds to the language learning in general will do the bricks mapping direction, this in itself will do parser of language. And concrete blocks programming languages ​​and programming is difficult to completely reasonable correspondence, especially Python, JavaScript supports object-oriented, functional programming, which has been difficult with the basic building blocks of a way to express.

  Again, not a good professor single step, breakpoint debugging such means. As for the one way, very easy to do to support these debug mode.

 

  Rebuilding a language

 

  As above, or turn the building into a string mapping, but without native programming language, but a language reconstruction.

  For example, the above language, this may be mapped to the following forms:

 

until >(i,100)
 set(k,sqrt(i))
 set(j,2)
 until or(>(j,k),=(%(i,j),0))
  add(j,1)
 end
 if >(j,k)
  echo(concatent(i,"是质数"))
 end
 add(i,1)
end

  The basic form of the above seems all function calls, although the wording is not the same as ordinary, but because there is no infix expression parsing all function, because the function of representation is very simple, basically the number of brackets on the line, so very easy to distinguish between the function name and the parameters, it is clear that the use of recursive function calls easily achieved here, and even write your own stack to resolve very simple. Keyword here only until, if, end, and thus can easily be interpreter.

  In particular, since it gives the interpreter language, nature can easily add a single step, breakpoint.

  Of course, really infix expression mapping will naturally be only slightly larger difficulty interpreter nothing.

  Scratch uses another similar manner, all data will be packaged json, the above described code format with the following paragraph array,

[["whenGreenFlag"],
        ["setVar:to:", "i", "2"],
        ["doUntil",
                [">", ["readVariable", "i"], "100"],
                [["setVar:to:", "k", ["computeFunction:of:", "sqrt", ["readVariable", "i"]]],
                        ["setVar:to:", "j", "2"],
                ["doUntil",
                        ["|",
                        [">", ["readVariable", "j"], ["readVariable", "k"]],
                                ["=", ["%", ["readVariable", "i"], ["readVariable", "j"]], "0"]],
                        [["changeVar:by:", "j", 1]]],
                ["doIf",
                        [">", ["readVariable", "j"], ["readVariable", "k"]],
                        [["say:duration:elapsed:from:", ["concatenate:with:", ["readVariable", "i"], "是质数"], 1]]],
        ["changeVar:by:", "i", 1]]]]

  This json analytic ways highly consistent with the way the whole function of the above, naturally highly consistent processing means.

  Of course, we can also use infix expression like this below

until i>100
 k=sqrt(i)
 j=2
 until j>k or i%j==0
  j+=1
 end
 if j>k
  echo(i,"是质数")
 end
 i+=1
end

  Infix expressions involving the operator priority issues, it is relatively complicated process. Of course, we can also use LEX / YACC to write a parser, it will be a lot easier, linux under LEX general use flex, YACC general use bison. But since the language here is basically just doing the intermediate language to use, it is not necessary to make such fundamental.

 

Figure computing

 

  Readers should be careful thought, since the graphical interface for the modeling process, the relationship between all the building blocks already a graph structure. The programming language compiler, the purpose is to bring into view of the structure of programming languages, since now have a structure diagram, generating an intermediate code looks but is more than just turn a bend, then we can use this figure is not directly calculate the structure it?

  In fact, of course, we can do the calculation by the graph structure. Obviously programmer intuition has direct calculation such as e.g. flowchart, our data structure contains a flow chart of each side (FIG directed graph is to have side direction) and the sense node.

   

 

   A schematic data structure as follows:

  Node:

    A : i<=1

    B(Switch) : i<100

    C: i Print

    D : i<=i+1

  Entrance:

     A

  Edge:

    A->B

    B(False)->C

    C->D

    D->A

    B(True)->End

 

Internal DSL - construction

 

  The so-called internal DSL, is based on the host language constructs a language of their own specific basis. This means that the new language is still virtually the host language, just constructed a lot of other things in the host language restrictions based on such makes it look very similar to a completely separate language. This is a completely different design methods previously designed.

  And we all know, Lisp is particularly good at designing DSL dry matter, especially Scheme, there are a variety of means can be designed. For example, we can be much stronger with macro macro (Macro), Lisp Tigers than the C language. Although the text is replaced by the macro, but Lisp macros support recursion, we can use Lisp macros do repeated recursively replaced, so we can replace our syntax tree with a very flexible way, even the syntax tree can be replaced with a macro " beyond recognition. " Scheme as well as the continuation of God, most DSL can be designed to process-oriented way, you can easily and continuation of process-oriented flow control modeled. More than two would be able to make Scheme do whatever they want, and remember there is a QBasic online is to use the Scheme to achieve this. Of course, we may again consider the more general Scheme programming, sub-package transitive closure operator in use, as we can design a good internal DSL.

  Here we do not intend to use other Lisp or Scheme to explain, here still with our usual host language, such as Python. In fact, Python is a very high degree of an abstract language, it is less than the Scheme of things in my opinion and also Acer continuation, then there is no tail recursion optimization.

 

  We consider such a program,

repeat 3 (
  repeat 4 (
    display("=")
  )
  newline()
  display("test")
  newline()
)
display("The end")
newline()

 

  Although, maybe I did not explain this meaning of this procedure, you should have already come up with the output of this program may be battle-hardened

====
test
====
test
====
test
The end

  

  Here repeat n (...) represents the contents of the brackets execute n times, and the display function is to print out the contents of the back, newline function is to wrap. This is a simple DSL, but on the basis of this principle we can actually do, such as painting like the program because painting is not constructed to teach children programming in general used too cumbersome graphics, from a you can start to think how to draw a whole, so you can take advantage of the cycle, without the need to use judgment (however, the picture may not be the sense of the complex, may be constantly added content in accordance with drawn after the current content of the decision, which may have required determination).

  Scratch Paint in the following example:

  

 

  The result is draw a regular hexagon as follows: 

  

 

   The DSL and said substantially uniform.

 

  But since it is want to do an internal DSL in Python, we have to think of a way to embed Python, is the most natural procedure before the rewrite is as follows:

run(
        repeat(3,
                repeat(4,
                        display("=")
                ),
                newline(),
                display("test"),
                newline()
        ),
        display("The end"),
        newline()
)

   Since there is no Scheme of Macro and Continuation, which is way above the Python function call, just put a little row format, with indented, thus easier to see semantics.

 

  The next consideration is how to achieve specific:

  We start with the display began, the first instinct is to display and Python print is the same.

  So we designed this way:

def display(s):
    print(s)

  It looks like we usually single display are OK, but soon we realized that like repeat (2, display ( "test")) such a program does not work, because there is no other influence after display print, repeat nature do not know display of action, so it can not replicate the action.

  Thus display needs a little influence to work properly, a way is passed through a variable out, which means there is a side effect, a lot of time should try to avoid. Thus, we consider only the return value from display to solve the problem. That is, information display function needs to return the display parameters and display of, newline also need to return the information contained newline, repeat and repeat it also returns information for all parameters.

  Most obvious, of course, is to use a string to represent this information.  

def display(a):
        return "display " + a

def newline():
        return "newline"

  Then we went on to write repeat,

from functools import reduce
def repeat(times, *args):
        s = "repeat " + str(times) + '\n(\n'
        for arg in args:
                s += reduce(lambda a,b:a+b,map(lambda x:' '+x+'\n',arg.split('\n')))
        s += ")"
        return s

We run about

  print(repeat(2, display("test")))

  get

repeat 2
(
display test
)

  Suddenly I realized that this wrong ah, so go on, run function completely into a language interpreter, exactly like this before and we are discussing. Then we will not return the string, return tuple, list data structure like it? A new name, or the case, there is nothing new.

  

Closure Construction

 

  The return value can not avoid the question to include functions and function parameters, but we can use other ways to do it, that is closure.

  The so-called closure, an operator, a function of the parameter information into another sealing function, this function returns the final, give a simple example the following should be very clear.

def addn(n):
    def f(x):
        return x+n
    return f

  Or use lambda, written above

    addn = lambda n:lambda x:x+n

  When in use, for example, I want a function that returns the number of input to get the result plus one, then addn (1) it is a function of what I need.

  addn is a closure.

 

  According to this idea, let's think about how to run a function to write, run a series of parameters is a function of the operation to take place in chronological order, then just run in order to perform these functions.

def run(*args):
        for arg in args:
                arg()

 

  Then, we try to write display and newline, the code can be as follows:

def display(s):
        def f():
                print(s, end="")
        return f

def newline():
        def f():
                print("")
        return f

   

  We found that the use of run, display, newline allows complete operating results with our thoughts.

  Then there is the repeat.

  For example, repeat (3, display ( "a"), newline ()), in fact, it should be a function that returns the execution result is three cycles to perform display ( "a") and newline () function returns, although getting a little hard to pronounce, but the code is not too complicated:  

def repeat(times, *args):
        def f():
                for i in range(times):
                        for arg in args:
                                arg()
        return f

 

  So far, the easiest contains only repeat, display, newline of DSL has been completed.

  We run the code design at the beginning, and did get the results you want.

 

Upgrade ideas

 

  Above this DSL is too simple, although it has circulation, but does not introduce variable, naturally there will be no introduction of operation, not a conditional branch.

  Then everything from variable starting, running in the process, in addition to the position of the currently running program, there are other state variables indicate a process-oriented programming. Before we repeat, display, newline return functions are no parameters, so that in addition to creating a function with side effects, or can not carry the message to other state transitions.

  So we can consider using a dictionary to represent the state of all variables in the program, and let all the closures eventually return with a dictionary to express such variables as parameters functions.

  So in this case, run function should be written like this:

def run (* args): 
        var_list = {}
         for angry into args: 
                var_list = arg (var_list)

  Above run_list what we need representatives dictionary for all variables.

  On this basis, we can construct a function used to set variables and functions to obtain variables:

def set_value(k, v):
        def f(var_list):
                var_list[k] = to_value(v, var_list)
                return var_list
        return f
def get_value(k):
        return lambda var_list : var_list[k]

  Rewriting display and newline, return of function parameters should of course add var_list, although the two are not directly associated with the variable, but it seems that only need to be returned directly to var_list to ensure proper closure can run as well as other calls.

def display(s):
        def f(var_list):
                print(s, end="")
                return var_list
        return f

def newline():
        def f(var_list):
                print("")
                return var_list
        return f

   However, we did not actually reflect on, then later display if it is constant, then the realization of the above and without error, but if it is not a constant? For example display (get_value ( "i")), get_value ( "i") is a function of the value of the desired print can not be printed clearly printed.

  So we should logically determine what display this parameter s, if it is a function, it should first be evaluated and then print.

def display(s):
        def f(var_list):
                if type(s)==type(lambda x:x):
                        print(s(var_list),end="")
                else:
                        print(s, end="")
                return var_list
        return f

  S type is a function of the determination, may also be used

  from types import FunctionType

  isinstance(a, FunctionType)

  We can test the above piece of code

run(
        set_value("i", 1),
        repeat(3,
                display(get_value("i")),
                newline()
        )
)

  Operating results are

1

1

1

  Consistent with our imagination, so basically verify its correctness.

 

  Of course, this is just start a discussion about, and not related to computing, conditional branching, conditional loop and continue, break, and even goto, even variable scope, functions, and so on. Even in this mode, we can even add debug mode, adding a single step, breakpoint debugging and other means.

  For specific approach here is no longer unfold, the reader can think on their own.

  The beginning of the program

  

  Stuff introduced with respect to the paper a little more, we now finally have a little prospect of a solution. As shown in the following detailed program code file, without elaborate.

                                                                                                           

 

Thinking of children's educational programming

 

  一个致力于少儿编程教育的朋友跟我聊天,说到新接手的一个班,虽然之前都在另一少儿编程平台下学习了近一年,但却连最基本的编程逻辑都不懂。虽然少儿编程教的一般是面向过程的编程,可是班上没有一个小朋友可以理解流程图这个东西。质数判断本应是个很简单的问题(当然,我们先不深入的看待此问题),然而甚至于他在班上把详细的过程描述清楚了,小朋友也会按照过程用纸笔来判断,可是一上程序全班没有一个人可以写出来。这位朋友很生气,觉得连流程图都不纳入教学体系是个很过分的事情,因为流程图是面向过程编程的基本抽象。小朋友最终连这么简单的程序都编不出来只能说明之前的教学简直就是应付,甚至欺骗。

  而我倒是跟他大谈或许教学目的该为如何教会小朋友一步步学会自己制作少儿编程工具,当然可能是针对对编程非常感兴趣的孩子。现实是,这样的孩子少,可以这样教的老师也少,从而无法产生合理的商业利益。于是,如何教好更多的孩子才是他所认为的教育之重。

  我一向认为老师教学生,不是复制自己,而是教会学生思考的方法。孩子学会思考的方法远比手把手的做个老师的克隆更强,独立做出一个程序,即使再烂,其价值远超过老师全力指导下写的高深程序。

  于是,还是应该把目光放回到我们目前教学的工具上,如何让孩子真正的理解程序,倒未必一直要从纯数学出发,也不需要什么高深算法,什么函数式编程,先掌握面向过程的精髓吧,让孩子可以自由的产生想法,再由想法变成代码。时机成熟了,再告诉孩子,某些东西可以有,比如算法,比如各种编程范式。当年日本围棋,超一流棋手的摇篮木谷道场,老师对于学生不按老师的想法行棋都是要惩罚的,然而六大超一流棋手风格各异,并没有按照老师的手段来行棋。换句话说,教育中,传承是根,但挖掘潜力才更为重要。

Guess you like

Origin www.cnblogs.com/Colin-Cai/p/11601046.html