{ "metadata": { "language": "Julia", "name": "", "signature": "sha256:6f4ffe27802546bed9ef87092586f49c78c6d17259042a6147ce8265e7c7271d" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Meta-ness" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Julia allows us to talk in a \"meta\" way (\"one level up\"), about Julia code, that is to \"treat code as data\" and manipulate it as just another object in Julia. (This is very similar to Lisp.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The basic objects in this approach are unevaluated *symbols*:" ] }, { "cell_type": "code", "collapsed": false, "input": [ ":a # \"the symbol a\"" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ ":a" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "typeof(:a)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 4, "text": [ "Symbol" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "`:a` refers to the symbol `a`. We can evaluate it with the `eval` function:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "eval(:a)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "a not defined\nwhile loading In[5], in expression starting on line 1", "output_type": "pyerr", "traceback": [ "a not defined\nwhile loading In[5], in expression starting on line 1" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "`a` must be defined for this to work:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = 3" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 6, "text": [ "3" ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "eval(:a)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 7, "text": [ "3" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `eval` function takes an expression and evaluates it, that is, *generates the corresponding code*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Everything is a symbol:" ] }, { "cell_type": "code", "collapsed": false, "input": [ ":+, :sin" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 8, "text": [ "(:+,:sin)" ] } ], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "typeof(:+)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 9, "text": [ "Symbol" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Symbols may be combined into *expressions*, which are the basic objects that represent pieces of Julia code:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ex = :(a + b) # the expression 'a+b'" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 10, "text": [ ":(a + b)" ] } ], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "typeof(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 11, "text": [ "Expr" ] } ], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "ex" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 12, "text": [ ":(a + b)" ] } ], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": [ "b = 7\n", "eval(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 13, "text": [ "10" ] } ], "prompt_number": 13 }, { "cell_type": "markdown", "metadata": {}, "source": [ "An expression is just a Julia object, so we can introspect (find out information about it):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "names(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 60, "text": [ "3-element Array{Symbol,1}:\n", " :head\n", " :args\n", " :typ " ] } ], "prompt_number": 60 }, { "cell_type": "code", "collapsed": false, "input": [ "# ex." ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 61 }, { "cell_type": "code", "collapsed": false, "input": [ "ex.head" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 14, "text": [ ":call" ] } ], "prompt_number": 14 }, { "cell_type": "code", "collapsed": false, "input": [ "ex.args" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 63, "text": [ "3-element Array{Any,1}:\n", " :+\n", " :a\n", " :b" ] } ], "prompt_number": 63 }, { "cell_type": "code", "collapsed": false, "input": [ "ex.typ" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 64, "text": [ "Any" ] } ], "prompt_number": 64 }, { "cell_type": "markdown", "metadata": {}, "source": [ "More complicated expressions are represented as \"abstract syntax trees\" (ASTs), consisting of expressions nested inside expressions:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ex = :( sin(3a + 2b^2) )" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 15, "text": [ ":(sin(3a + 2 * b^2))" ] } ], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "ex.args" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 16, "text": [ "2-element Array{Any,1}:\n", " :sin \n", " :(3a + 2 * b^2)" ] } ], "prompt_number": 16 }, { "cell_type": "code", "collapsed": false, "input": [ "typeof(ex.args[2])" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 17, "text": [ "Expr" ] } ], "prompt_number": 17 }, { "cell_type": "code", "collapsed": false, "input": [ "ex.args[2].args" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 18, "text": [ "3-element Array{Any,1}:\n", " :+ \n", " :(3a) \n", " :(2 * b^2)" ] } ], "prompt_number": 18 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Expressions can be arbitrary Julia code that when evaluated will have side effects. For longer blocks of code, `quote...end` may be used instead of `:( ... )`" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ex2 = \n", "quote\n", " y = 3\n", " z = sin(y+1)\n", "end\n", " " ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 19, "text": [ ":(begin # In[19], line 3:\n", " y = 3 # line 4:\n", " z = sin(y + 1)\n", " end)" ] } ], "prompt_number": 19 }, { "cell_type": "code", "collapsed": false, "input": [ "y" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "y not defined\nwhile loading In[70], in expression starting on line 1", "output_type": "pyerr", "traceback": [ "y not defined\nwhile loading In[70], in expression starting on line 1" ] } ], "prompt_number": 70 }, { "cell_type": "code", "collapsed": false, "input": [ "eval(ex2)\n", "z" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 71, "text": [ "-0.7568024953079282" ] } ], "prompt_number": 71 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The full form of the abstract syntax tree in a style similar to a Lisp s-expression can be obtained using functions from the `Meta` module in `Base`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "Meta.show_sexpr(ex2)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "(:" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "block,\n", " (:line, 3, :In[19]),\n", " (:(=), :y, 3),\n", " :( # line 4:),\n", " (:(=), :z, (:call, :sin, (:call, :+, :y, 1)))\n", ")" ] } ], "prompt_number": 20 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another way of seeing the structure is with `dump`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "dump(ex2)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Expr " ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", " head: Symbol block\n", " args: Array(Any,(4,))\n", " 1: Expr \n", " head: Symbol line\n", " args: Array(Any,(2,))\n", " 1: Int64" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 3\n", " 2: Symbol In[19]\n", " typ: Any\n", " 2: Expr \n", " head: Symbol =\n", " args: Array(Any,(2,))\n", " 1: Symbol y\n", " 2: Int64 3\n", " typ: Any\n", " 3: LineNumberNode \n", " line: Int64 4\n", " 4: Expr \n", " head: Symbol =\n", " args: Array(Any,(2,))\n", " 1: Symbol z\n", " 2: Expr \n", " head: Symbol call\n", " args: Array(Any,(2,))\n", " typ: Any\n", " typ: Any\n", " typ: Any\n" ] } ], "prompt_number": 21 }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Macros" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With the ability to think of code in terms of a data structure in the Julia language, we can now *manipulate* those data structures, allowing us to *create Julia code on the fly from within Julia*. This is known as *metaprogramming*: programming a program.\n", "\n", "The name *macro* is given to a kind of \"super-function\" that takes a piece of code as an argument, and returns an altered piece of code. A macro is thus a very different kind of object than a standard function. [Although it can be thought of as a function in the mathematical sense of the word.]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The [Julia manual](http://julia.readthedocs.org/en/latest/manual/metaprogramming/) puts it like this: \n", "\n", "> macros map a tuple of argument *expressions* to a returned\n", "> *expression*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Although metaprogramming is possible in many languages (including Python), Julia makes it particularly natural (although not exactly \"easy\"!)\n", "\n", "Metaprogramming is useful in a variety of settings:\n", "- to eliminate boilerplate (repetitive) code\n", "- to automatically generate complex code that would be painful by hand\n", "- to unroll loops for efficiency\n", "- to inline code for efficiency\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Macros are invoked using the `@` sign, e.g." ] }, { "cell_type": "code", "collapsed": false, "input": [ "@time sin(10)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "elapsed time: 0." ] }, { "output_type": "stream", "stream": "stdout", "text": [ "004374081 seconds (47856 bytes allocated)\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 22, "text": [ "-0.5440211108893698" ] } ], "prompt_number": 22 }, { "cell_type": "markdown", "metadata": {}, "source": [ "A trivial example of defining a macro is the following, which duplicates whatever code it is passed. The `$` sign is used to interpolate the value of the expression (similar to its usage for string interpolation):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "macro duplicate(ex)\n", " quote\n", " $ex\n", " $ex\n", " end\n", "end" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 23 }, { "cell_type": "code", "collapsed": false, "input": [ "@duplicate println(sin(10))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "-0." ] }, { "output_type": "stream", "stream": "stdout", "text": [ "5440211108893698\n", "-0.5440211108893698\n" ] } ], "prompt_number": 24 }, { "cell_type": "code", "collapsed": false, "input": [ "ex = :(@duplicate println(sin(10)))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 25, "text": [ ":(@duplicate println(sin(10)))" ] } ], "prompt_number": 25 }, { "cell_type": "code", "collapsed": false, "input": [ "eval(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "-0." ] }, { "output_type": "stream", "stream": "stdout", "text": [ "5440211108893698\n", "-0.5440211108893698\n" ] } ], "prompt_number": 77 }, { "cell_type": "code", "collapsed": false, "input": [ "typeof(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 78, "text": [ "Expr" ] } ], "prompt_number": 78 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see what effect the macro actually has using `macroexpand`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "macroexpand(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 26, "text": [ ":(begin # In[23], line 3:\n", " println(sin(10)) # line 4:\n", " println(sin(10))\n", " end)" ] } ], "prompt_number": 26 }, { "cell_type": "code", "collapsed": false, "input": [ "macroexpand(:(@time sin(10)))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 27, "text": [ ":(begin # util.jl, line 50:\n", " local #261#b0 = Base.gc_bytes() # line 51:\n", " local #262#t0 = Base.time_ns() # line 52:\n", " local #263#g0 = Base.gc_time_ns() # line 53:\n", " local #264#val = sin(10) # line 54:\n", " local #265#g1 = Base.gc_time_ns() # line 55:\n", " local #266#t1 = Base.time_ns() # line 56:\n", " local #267#b1 = Base.gc_bytes() # line 57:\n", " Base.time_print(Base.-(#266#t1,#262#t0),Base.-(#267#b1,#261#b0),Base.-(#265#g1,#263#g0)) # line 58:\n", " #264#val\n", " end)" ] } ], "prompt_number": 27 }, { "cell_type": "markdown", "metadata": {}, "source": [ "----\n", "**Exercise**: Define a macro `@until` that does an `until` loop.\n", "\n", "----" ] }, { "cell_type": "code", "collapsed": false, "input": [ "macro until(expr1, expr2)\n", " quote\n", " #:(\n", " while !($expr1) # code interpolation\n", " $expr2\n", " end\n", " #)\n", " end\n", "end" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 30 }, { "cell_type": "code", "collapsed": false, "input": [ "i = 0\n", "@until i==10 begin\n", " println(i)\n", " i += 1\n", "end" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "0\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "1\n", "2\n", "3\n", "4\n", "5\n", "6\n", "7\n", "8\n", "9\n" ] } ], "prompt_number": 34 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "A nontrivial example: Horner's method" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are many interesting examples of macros in `Base`. One that is accessible is Horner's method for evaluating a polynomial:\n", "\n", "$$p(x) = a_n x^n + a_{n-1} x^{n-1} + \\cdots + a_1 x^1 + a_0$$\n", "\n", "may be evaluated efficiently as\n", "\n", "$$p(x) = a_0 + x(a_1 + \\cdots x(a_{n-2} + \\cdots + x(a_{n-1} + x a_n) \\cdots ) ) $$\n", "with only $n$ multiplications.\n", "\n", "The obvious way to do this is with a `for` loop. But if we know the polynomial *at compile time*, this loop may be unrolled using metaprogramming. This is implemented in the `Math` module in `math.jl` in `Base`, so the name of the macro (which is not exported) is `@Base.Math.horner`\n", "\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "horner" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "horner not defined\nwhile loading In[35], in expression starting on line 1", "output_type": "pyerr", "traceback": [ "horner not defined\nwhile loading In[35], in expression starting on line 1" ] } ], "prompt_number": 35 }, { "cell_type": "code", "collapsed": false, "input": [ "# copied from base/math.jl\n", "macro horner(x, p...)\n", " ex = esc(p[end])\n", " for i = length(p)-1:-1:1\n", " ex = :( $(esc(p[i])) + t * $ex )\n", " end\n", " Expr(:block, :(t = $(esc(x))), ex)\n", "end" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 37 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is called as follows: to evaluate the polynomial $p(x) = 2 + 3x + 4x^2$ at $x=3$, we do" ] }, { "cell_type": "code", "collapsed": false, "input": [ "x = 3\n", "@horner(x, 2, 3, 4)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 38, "text": [ "47" ] } ], "prompt_number": 38 }, { "cell_type": "markdown", "metadata": {}, "source": [ "[Even though the Horner macro is not exported in `Base`, we can access it as `@Base.Math.horner`]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To see what the macro does to this call, we again use `macroexpand`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "macroexpand(:(@horner(x, 2, 3, 4)))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 39, "text": [ ":(begin \n", " #269#t = x\n", " 2 + #269#t * (3 + #269#t * 4)\n", " end)" ] } ], "prompt_number": 39 }, { "cell_type": "code", "collapsed": false, "input": [ "macroexpand(:(@Base.Math.horner(x, 2, 3, 4)))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 88, "text": [ ":(begin \n", " #292#t = x\n", " Base.Math.+(2,Base.Math.*(#292#t,Base.Math.+(3,Base.Math.*(#292#t,4))))\n", " end)" ] } ], "prompt_number": 88 }, { "cell_type": "code", "collapsed": false, "input": [ "x = 3.5\n", "@printf(\"%.5f\", x)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "3." ] }, { "output_type": "stream", "stream": "stdout", "text": [ "50000" ] } ], "prompt_number": 101 }, { "cell_type": "code", "collapsed": false, "input": [ "@printf" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "@printf: called with zero arguments\nwhile loading In[2], in expression starting on line 1", "output_type": "pyerr", "traceback": [ "@printf: called with zero arguments\nwhile loading In[2], in expression starting on line 1" ] } ], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "ex = :(@time sin(10))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 102, "text": [ ":(@time sin(10))" ] } ], "prompt_number": 102 }, { "cell_type": "code", "collapsed": false, "input": [ "Meta.show_sexpr(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "(:" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "macrocall, :@time, (:call, :sin, 10))" ] } ], "prompt_number": 103 }, { "cell_type": "code", "collapsed": false, "input": [ "xdump(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Expr " ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", " head: Symbol macrocall\n", " args: Array(Any,(2,))\n", " 1: Symbol @time\n", " 2: Expr \n", " head: Symbol call\n", " args: Array(Any,(2,))\n", " 1: Symbol sin\n", " 2: Int64" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 10\n", " typ: Any::DataType <: Any\n", " typ: Any::DataType <: Any\n" ] } ], "prompt_number": 5 }, { "cell_type": "code", "collapsed": false, "input": [ "macroexpand(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 6, "text": [ ":(begin # util.jl, line 50:\n", " local #254#b0 = Base.gc_bytes() # line 51:\n", " local #255#t0 = Base.time_ns() # line 52:\n", " local #256#g0 = Base.gc_time_ns() # line 53:\n", " local #257#val = sin(10) # line 54:\n", " local #258#g1 = Base.gc_time_ns() # line 55:\n", " local #259#t1 = Base.time_ns() # line 56:\n", " local #260#b1 = Base.gc_bytes() # line 57:\n", " Base.time_print(Base.-(#259#t1,#255#t0),Base.-(#260#b1,#254#b0),Base.-(#258#g1,#256#g0)) # line 58:\n", " #257#val\n", " end)" ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "@time sin(10)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "elapsed time: 0." ] }, { "output_type": "stream", "stream": "stdout", "text": [ "006097425 seconds (47856 bytes allocated)\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 7, "text": [ "-0.5440211108893698" ] } ], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "dump(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Expr " ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", " head: Symbol macrocall\n", " args: Array(Any,(2,))\n", " 1: Symbol @time\n", " 2: Expr \n", " head: Symbol call\n", " args: Array(Any,(2,))\n", " 1: Symbol sin\n", " 2: Int64 10\n", " typ: Any\n", " typ: Any\n" ] } ], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "xdump(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Expr " ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", " head: Symbol macrocall\n", " args: Array(Any,(2,))\n", " 1: Symbol @time\n", " 2: Expr \n", " head: Symbol call\n", " args: Array(Any,(2,))\n", " 1: Symbol sin\n", " 2: Int64 10\n", " typ: Any::DataType <: Any\n", " typ: Any::DataType <: Any\n" ] } ], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "type Vector2D{T <: Real}\n", " x::T\n", " y::T\n", "end" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "methods(Vector2D)" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "1 method for generic function Vector2D:" ], "metadata": {}, "output_type": "pyout", "prompt_number": 9, "text": [ "# 1 method for generic function \"Vector2D\":\n", "Vector2D{T<:Real}(x::T<:Real,y::T<:Real)" ] } ], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "v = Vector2D{Float64}(3, 4)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 10, "text": [ "Vector2D{Float64}(3.0,4.0)" ] } ], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "v = Vector2D(3., 4)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "no method Vector2D{T<:Real}(Float64, Int64)\nwhile loading In[11], in expression starting on line 1", "output_type": "pyerr", "traceback": [ "no method Vector2D{T<:Real}(Float64, Int64)\nwhile loading In[11], in expression starting on line 1" ] } ], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "v = Vector2D(3., 4.)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 18, "text": [ "Vector2D{Float64}(3.0,4.0)" ] } ], "prompt_number": 18 }, { "cell_type": "code", "collapsed": false, "input": [ "# clear" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "# uses show(io::IO, v::DataType) by default" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "typeof(Vector2D)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 15, "text": [ "DataType" ] } ], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "super(Vector2D)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 13, "text": [ "Any" ] } ], "prompt_number": 13 }, { "cell_type": "code", "collapsed": false, "input": [ "methods(show)" ], "language": "python", "metadata": {}, "outputs": [ { "html": [ "89 methods for generic function show:" ], "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ "# 89 methods for generic function \"show\":\n", "show(io::IO,r::UnitRange{T<:Real}) at range.jl:283\n", "show(io::IO,r::Range{T}) at range.jl:281\n", "show(io::IO,tv::TypeVar) at expr.jl:46\n", "show(io::IO,z::Complex{T<:Real}) at complex.jl:80\n", "show(io::IO,x::Rational{T<:Integer}) at rational.jl:35\n", "show(io::IO,s::IntSet) at intset.jl:170\n", "show(io::IO,::EnvHash) at env.jl:168\n", "show{K,V}(io::IO,t::Associative{K,V}) at dict.jl:20\n", "show(io::IO,iter::Union(KeyIterator{T<:Associative{K,V}},ValueIterator{T<:Associative{K,V}})) at dict.jl:118\n", "show(io::IO,s::Set{T}) at set.jl:10\n", "show(io::IO,c::Char) at char.jl:53\n", "show(io::IO,b::IOBuffer) at iobuffer.jl:27\n", "show(io::IO,s::String) at string.jl:69\n", "show(io::IO,re::Regex) at regex.jl:61\n", "show(io::IO,m::RegexMatch) at regex.jl:89\n", "show(io::IO,s::IOStream) at iostream.jl:26\n", "show(io::IO,t::Task) at task.jl:3\n", "show(io::IO,f::Function) at show.jl:57\n", "show(io::IO,x::IntrinsicFunction) at show.jl:67\n", "show(io::IO,x::UnionType) at show.jl:71\n", "show(io::IO,x::TypeConstructor) at show.jl:80\n", "show(io::IO,x::DataType) at show.jl:83\n", "show(io::IO,tn::TypeName) at show.jl:200\n", "show(io::IO,::Nothing) at show.jl:201\n", "show(io::IO,b::Bool) at show.jl:202\n", "show(io::IO,n::Signed) at show.jl:203\n", "show(io::IO,n::Unsigned) at show.jl:204\n", "show{T}(io::IO,p::Ptr{T}) at show.jl:116\n", "show(io::IO,m::Module) at show.jl:120\n", "show(io::IO,l::LambdaStaticData) at show.jl:128\n", "show(io::IO,t::(Any...,)) at show.jl:197\n", "show(io::IO,s::Symbol) at show.jl:199\n", "show(io::IO,ex::Union(LabelNode,LineNumberNode,Expr,GotoNode,SymbolNode,TopNode,QuoteNode)) at show.jl:234\n", "show(io::IO,W::Woodbury{T}) at linalg/woodbury.jl:42\n", "show(io::IO,M::Bidiagonal{T}) at linalg/bidiag.jl:56\n", "show(io::IO,v::AbstractArray{Any,1}) at show.jl:1102\n", "show(io::IO,v::AbstractArray{T,1}) at show.jl:1103\n", "show(io::IO,X::AbstractArray{T,N}) at show.jl:1038\n", "show(io::IO,stream::Pipe) at stream.jl:171\n", "show(io::IO,stream::PipeServer) at stream.jl:173\n", "show(io::IO,stream::TTY) at stream.jl:215\n", "show(io::IO,e::UVError) at stream.jl:824\n", "show(io::IO,ip::IPv4) at socket.jl:29\n", "show(io::IO,ip::IPv6) at socket.jl:81\n", "show(io::IO,sock::TcpSocket) at socket.jl:324\n", "show(io::IO,sock::TcpServer) at socket.jl:327\n", "show(io::IO,st::StatStruct) at stat.jl:31\n", "show(io::IO,cmd::Cmd) at process.jl:33\n", "show(io::IO,cmds::OrCmds) at process.jl:51\n", "show(io::IO,cmds::AndCmds) at process.jl:69\n", "show(io::IO,cr::CmdRedirect) at process.jl:123\n", "show(io::IO,p::Process) at process.jl:622\n", "show{mime}(io::IO,::MIME{mime}) at multimedia.jl:16\n", "show(io::IO,x::Float64) at grisu.jl:114\n", "show(io::IO,x::Float32) at grisu.jl:115\n", "show(io::IO,x::Float16) at grisu.jl:116\n", "show(io::IO,m::Method) at methodshow.jl:35\n", "show(io::IO,mt::MethodTable) at methodshow.jl:74\n", "show(io::IO,cman::LocalManager) at multi.jl:1109\n", "show(io::IO,cman::SSHManager) at multi.jl:1144\n", "show(io::IO,x::BigInt) at gmp.jl:417\n", "show(io::IO,b::BigFloat) at mpfr.jl:762\n", "show(io::IO,u::UUID) at random.jl:297\n", "show(io::IO,v::VersionNumber) at version.jl:57\n", "show(io::IO,x::Prompt) at LineEdit.jl:48\n", "show(io::IO,C::Cholesky{T}) at linalg/factorization.jl:83\n", "show(io::IO,J::UniformScaling{T<:Number}) at linalg/uniformscaling.jl:14\n", "show(io::IO,f::UmfpackLU{Tv<:Union(Float64,Complex{Float64}),Ti<:Union(Int64,Int32)}) at linalg/umfpack.jl:134\n", "show(io::IO,cd::CholmodDense{T<:Union(Complex{Float32},Float64,Float32,Complex{Float64})}) at linalg/cholmod.jl:382\n", "show(io::IO,L::CholmodFactor{Tv<:Union(Complex{Float32},Float64,Float32,Complex{Float64}),Ti<:Union(Int64,Int32)}) at linalg/cholmod.jl:914\n", "show(io::IO,A::CholmodSparse{Tv<:Union(Complex{Float32},Float64,Float32,Complex{Float64}),Ti<:Union(Int64,Int32)}) at linalg/cholmod.jl:915\n", "show(io::IO,info::CPUinfo) at sysinfo.jl:58\n", "show(io::IO,info::CPUinfo,header::Bool) at sysinfo.jl:58\n", "show(io::IO,info::CPUinfo,header::Bool,prefix::String) at sysinfo.jl:58\n", "show{sym}(io::IO,x::MathConst{sym}) at constants.jl:5\n", "show(io::IO,i::VersionInterval) at pkg/types.jl:13\n", "show(io::IO,s::VersionSet) at pkg/types.jl:36\n", "show(io::IO,a::Available) at pkg/types.jl:69\n", "show(io::IO,f::Fixed) at pkg/types.jl:81\n", "show(io::IO,blk::DequeBlock{T}) at /Users/david/.julia/DataStructures/src/deque.jl:46\n", "show(io::IO,q::Deque{T}) at /Users/david/.julia/DataStructures/src/deque.jl:139\n", "show(io::IO,h::MutableBinaryHeap{VT,Comp}) at /Users/david/.julia/DataStructures/src/heaps/mutable_binary_heap.jl:177\n", "show(io::IO,s::OrderedSet{T}) at /Users/david/.julia/DataStructures/src/orderedset.jl:18\n", "show{T}(io::IO,l::LinkedList{T}) at /Users/david/.julia/DataStructures/src/list.jl:20\n", "show{T<:HashAlgorithm}(io::IO,::HashState{T<:HashAlgorithm}) at /Users/david/.julia/Nettle/src/hash.jl:94\n", "show{T<:HashAlgorithm}(io::IO,::HMACState{T<:HashAlgorithm}) at /Users/david/.julia/Nettle/src/hmac.jl:16\n", "show(io::IO,msg::Msg) at /Users/david/.julia/IJulia/src/msg.jl:38\n", "show(io::IO,x::ANY) at show.jl:7\n", "show(x) at show.jl:2" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "Base.show(io::IO, v::Vector2D) = print(io, \"[$(v.x), $(v.y)]\")" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 20, "text": [ "show (generic function with 91 methods)" ] } ], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "v" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 18, "text": [ "[3.0, 4.0]" ] } ], "prompt_number": 18 }, { "cell_type": "code", "collapsed": false, "input": [ "Vector2D(3im, 4im)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "no method Vector2D{T<:Real}(Complex{Int64}, Complex{Int64})\nwhile loading In[19], in expression starting on line 1", "output_type": "pyerr", "traceback": [ "no method Vector2D{T<:Real}(Complex{Int64}, Complex{Int64})\nwhile loading In[19], in expression starting on line 1" ] } ], "prompt_number": 19 }, { "cell_type": "code", "collapsed": false, "input": [ "code = \n", "\"\"\"\n", "function testinf(a, b)\n", " y = a + b\n", " return sin(y)\n", "end\n", "\"\"\"\n", "ex = parse(code)\n", "eval(ex)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 29, "text": [ "testinf (generic function with 1 method)" ] } ], "prompt_number": 29 }, { "cell_type": "code", "collapsed": false, "input": [ "function testinf(a, b)\n", " y = a + b\n", " return sin(y)\n", "end\n" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 21, "text": [ "testinf (generic function with 1 method)" ] } ], "prompt_number": 21 }, { "cell_type": "code", "collapsed": false, "input": [ "code_lowered(testinf,(Int, Int))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 24, "text": [ "1-element Array{Any,1}:\n", " :($(Expr(:lambda, {:a,:b}, {{:y},{{:a,:Any,0},{:b,:Any,0},{:y,:Any,18}},{}}, :(begin # In[21], line 2:\n", " y = a + b # line 3:\n", " return sin(y)\n", " end))))" ] } ], "prompt_number": 24 }, { "cell_type": "code", "collapsed": false, "input": [ "code_typed(testinf, (Int, Int))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 22, "text": [ "1-element Array{Any,1}:\n", " :($(Expr(:lambda, {:a,:b}, {{:y,:_var1},{{:a,Int64,0},{:b,Int64,0},{:y,Int64,18},{:_var1,Float64,18}},{}}, :(begin # In[21], line 2:\n", " y = top(box)(Int64,top(add_int)(a::Int64,b::Int64))::Int64 # line 3:\n", " _var1 = GetfieldNode(Base.Math,:box,Any)(Float64,top(sitofp)(Float64,y::Int64))::Float64\n", " return GetfieldNode(Base.Math,:nan_dom_err,Any)(top(ccall)($(Expr(:call1, :(top(tuple)), \"sin\", GetfieldNode(Base.Math,:libm,Any)))::(ASCIIString,ASCIIString),Float64,$(Expr(:call1, :(top(tuple)), :Float64))::(Type{Float64},),_var1::Float64,0)::Float64,_var1::Float64)::Float64\n", " end::Float64))))" ] } ], "prompt_number": 22 }, { "cell_type": "code", "collapsed": false, "input": [ "code_typed(testinf, (Float64, Float64))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 23, "text": [ "1-element Array{Any,1}:\n", " :($(Expr(:lambda, {:a,:b}, {{:y},{{:a,Float64,0},{:b,Float64,0},{:y,Float64,18}},{}}, :(begin # In[21], line 2:\n", " y = top(box)(Float64,top(add_float)(a::Float64,b::Float64))::Float64 # line 3:\n", " return GetfieldNode(Base.Math,:nan_dom_err,Any)(top(ccall)($(Expr(:call1, :(top(tuple)), \"sin\", GetfieldNode(Base.Math,:libm,Any)))::(ASCIIString,ASCIIString),Float64,$(Expr(:call1, :(top(tuple)), :Float64))::(Type{Float64},),y::Float64,0)::Float64,y::Float64)::Float64\n", " end::Float64))))" ] } ], "prompt_number": 23 }, { "cell_type": "code", "collapsed": false, "input": [ "code_llvm(testinf, (Int, Int))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\n", "define double @\"julia_testinf;19510\"(i64, i64) {\n", "top:\n", " %2 = add i64 %1, %0, !dbg !2501\n", " %3 = sitofp i64 %2 to double, !dbg !2502\n", " %4 = call double inttoptr (i64 4514612992 to double (double)*)(double %3), !dbg !2502\n", " %5 = fcmp ord double %4, 0.000000e+00, !dbg !2502\n", " %6 = fcmp uno double %3, 0.000000e+00, !dbg !2502\n", " %7 = or i1 %5, %6, !dbg !2502\n", " br i1 %7, label %pass, label %fail, !dbg !2502\n", "\n", "fail: ; preds = %top\n", " %8 = load %jl_value_t** @jl_domain_exception, align 8, !dbg !2502, !tbaa %jtbaa_const\n", " call void @jl_throw_with_superfluous_argument(%jl_value_t* %8, i32 3), !dbg !2502\n", " unreachable, !dbg !2502\n", "\n", "pass: ; preds = %top\n", " ret double %4, !dbg !2502\n", "}\n" ] } ], "prompt_number": 25 }, { "cell_type": "code", "collapsed": false, "input": [ "code_native(testinf, (Int, Int))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\t.section\t__TEXT,__text,regular,pure_instructions\n", "Filename: In[21]\n", "Source line: 2\n", "\tpush\tRBP\n", "\tmov\tRBP, RSP\n", "Source line: 2\n", "\tsub\tRSP, 16\n", "\tadd\tRDI, RSI\n", "Source line: 3\n", "\tvcvtsi2sd\tXMM0, XMM0, RDI\n", "\tvmovsd\tQWORD PTR [RBP - 8], XMM0\n", "\tmovabs\tRAX, 4514612992\n", "\tcall\tRAX\n", "\tvucomisd\tXMM0, XMM0\n", "\tjp\t6\n", "\tadd\tRSP, 16\n", "\tpop\tRBP\n", "\tret\n", "\tvmovsd\tXMM1, QWORD PTR [RBP - 8]\n", "\tvucomisd\tXMM1, XMM1\n", "\tjp\t-21\n", "\tmovabs\tRAX, 4380089384\n", "\tmov\tRDI, QWORD PTR [RAX]\n", "\tmovabs\tRAX, 4367555552\n", "\tmov\tESI, 3\n", "\tcall\tRAX\n" ] } ], "prompt_number": 26 }, { "cell_type": "code", "collapsed": false, "input": [ "names(testinf)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 32, "text": [ "3-element Array{Symbol,1}:\n", " :fptr\n", " :env \n", " :code" ] } ], "prompt_number": 32 }, { "cell_type": "code", "collapsed": false, "input": [ "testinf.fptr" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 34, "text": [ "Ptr{Void} @0x00000001044f2e50" ] } ], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": [ "testinf.code" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "access to undefined reference\nwhile loading In[38], in expression starting on line 1", "output_type": "pyerr", "traceback": [ "access to undefined reference\nwhile loading In[38], in expression starting on line 1" ] } ], "prompt_number": 38 }, { "cell_type": "code", "collapsed": false, "input": [ "?dump" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stderr", "text": [ "INFO: Loading help data...\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "Base.dump(x)\n", "\n", " Show all user-visible structure of a value.\n" ] } ], "prompt_number": 11 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Possible solution of the `@until` exercise:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "macro until(ex1, ex2)\n", " quote\n", " while !($ex1)\n", " $ex2\n", " end\n", " end\n", "end" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "i = 1\n", "\n", "@until i > 10 begin\n", " println(i)\n", " i += 1\n", "end" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1\n" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "2\n", "3\n", "4\n", "5\n", "6\n", "7\n", "8\n", "9\n", "10\n" ] } ], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "i = 1\n", "\n", "@until i > 10 \n", "begin\n", " println(i)\n", " i += 1\n", "end" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "wrong number of arguments\nwhile loading In[11], in expression starting on line 4", "output_type": "pyerr", "traceback": [ "wrong number of arguments\nwhile loading In[11], in expression starting on line 4" ] } ], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ ":while" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 13, "text": [ ":while" ] } ], "prompt_number": 13 }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }