Skip to content

Instantly share code, notes, and snippets.

@oxinabox
Last active November 19, 2015 07:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oxinabox/50a1e17cfb232a7d1908 to your computer and use it in GitHub Desktop.
Save oxinabox/50a1e17cfb232a7d1908 to your computer and use it in GitHub Desktop.
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"#WRT https://github.com/JuliaLang/julia/issues/5571#issuecomment-157608127"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Copyright (c) 2015 Lyndon White aka oxinabox aka Frames\n",
"\n",
"\n",
"Permission is hereby granted, free of charge, to any person obtaining a copy\n",
"of this software and associated documentation files (the \"Software\"), to deal\n",
"in the Software without restriction, including without limitation the rights\n",
"to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n",
"copies of the Software, and to permit persons to whom the Software is\n",
"furnished to do so, subject to the following conditions:\n",
"\n",
"\n",
"The above copyright notice and this permission notice shall be included in\n",
"all copies or substantial portions of the Software.\n",
"\n",
"\n",
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n",
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n",
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n",
"THE SOFTWARE.\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"terse_lambda (generic function with 1 method)"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function terse_lambda(l_args::Vector{Symbol}, new_ff::Expr) \n",
" if length(l_args)==0\n",
" return new_ff \n",
" elseif length(l_args)==1\n",
" Expr(:->,\n",
" l_args[1],\n",
" new_ff\n",
" )\n",
" else\n",
" Expr(:->,\n",
" Expr(:tuple,l_args...),\n",
" new_ff\n",
" )\n",
" end\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"terse_treechange (generic function with 1 method)"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function terse_treechange(ff::Expr)\n",
" #Need to search the tree from left most node, to right\n",
" #This is depth first I think (CHKLOGIC)\n",
" function rec(path::Vector{Int},gg::Expr)\n",
" new_tail = Any[]\n",
" l_args = Symbol[]\n",
" \n",
" for (child_ii, hh) in enumerate(gg.args)\n",
" if typeof(hh)==Expr\n",
" c_path=[path...,child_ii]\n",
" new_hh, c_l_args = rec(c_path,hh)\n",
" if length(c_l_args)>0\n",
" push!(l_args, c_l_args...)\n",
" end\n",
" push!(new_tail, new_hh)\n",
" elseif hh==:_\n",
" path_str = join(path,\"b\")\n",
" #There may be a way to use the existing hygine mechnanism's to avoid a nameclash here\n",
" #For now I describe them with the path\n",
" c_l_arg = Symbol(\"xx$(path_str)t$(child_ii)\")\n",
" \n",
" push!(l_args, c_l_arg)\n",
" push!(new_tail, c_l_arg)\n",
" else\n",
" push!(new_tail, hh)\n",
" end\n",
" end\n",
" new_gg = Expr(gg.head, new_tail...)\n",
" (new_gg, l_args)\n",
" end\n",
" new_ff, ol_args = rec(Int[], ff)\n",
" terse_lambda(ol_args, new_ff)\n",
"end\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"terse! (generic function with 2 methods)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function terse!(ff)\n",
" ff\n",
"end\n",
"function terse!(ff::Expr)\n",
" const prec_other = Set(map(Symbol,[\"->\", \"if\"]))\n",
" const prec_assignment = Set(map(Symbol,[\"=\", \":=\", \"+=\", \"-=\", \"*=\", \"/=\", \"//=\", \".//=\", \".*=\", \"./=\", \"|\\\\=|\", \"|.\\\\=|\", \"^=\", \".^=\", \"÷=\", \".÷=\", \"%=\", \".%=\", \"|\\|=|\", \"&=\", \"\\$=\", \"=>\", \"<<=\", \">>=\", \">>>=\", \"~\", \"|.+=|\", \"|.-=|\"]))\n",
" const prec_conditional = Set([:?])\n",
" const prec_arrow = Set(map(Symbol,[\"\", \"'(--\", \"-->\", \"←\", \"→\", \"↔\", \"↚\", \"↛\", \"↠\", \"↣\", \"↦\", \"↮\", \"⇎\", \"⇏\", \"⇒\", \"⇔\", \"⇴\", \"⇶\", \"⇷\", \"⇸\", \"⇹\", \"⇺\", \"⇻\", \"⇼\", \"⇽\", \"⇾\", \"⇿\", \"⟵\", \"⟶\", \"⟷\", \"⟷\", \"⟹\", \"⟺\", \"⟻\", \"⟼\", \"⟽\", \"⟾\", \"⟿\", \"⤀\", \"⤁\", \"⤂\", \"⤃\", \"⤄\", \"⤅\", \"⤆\", \"⤇\", \"⤌\", \"⤍\", \"⤎\", \"⤏\", \"⤐\", \"⤑\", \"⤔\", \"⤕\", \"⤖\", \"⤗\", \"⤘\", \"⤝\", \"⤞\", \"⤟\", \"⤠\", \"⥄\", \"⥅\", \"⥆\", \"⥇\", \"⥈\", \"⥊\", \"⥋\", \"⥎\", \"⥐\", \"⥒\", \"⥓\", \"⥖\", \"⥗\", \"⥚\", \"⥛\", \"⥞\", \"⥟\", \"⥢\", \"⥤\", \"⥦\", \"⥧\", \"⥨\", \"⥩\", \"⥪\", \"⥫\", \"⥬\", \"⥭\", \"⥰\", \"⧴\", \"⬱\", \"⬰\", \"⬲\", \"⬳\", \"⬴\", \"⬵\", \"⬶\", \"⬷\", \"⬸\", \"⬹\", \"⬺\", \"⬻\", \"⬼\", \"⬽\", \"⬾\", \"⬿\", \"⭀\", \"⭁\", \"⭂\", \"⭃\", \"⭄\", \"⭇\", \"⭈\", \"⭉\", \"⭊\", \"⭋\", \"⭌\", \"←\", \"→))\"]))\n",
" const prec_above = union(prec_other, prec_assignment,prec_conditional, prec_arrow)\n",
"\n",
" function high_prec_node(gg::Expr)\n",
" gg.head in prec_above\n",
" end\n",
" \n",
" const prec_below = Set([:*,:+,:-,:/,:÷]) #Their many be others\n",
" function low_prec_node(gg::Expr)\n",
" #Certain nodes should not be transformed inside of, even if they are the top node\n",
" gg.head == :call && gg.args[1] in prec_below\n",
" end\n",
" \n",
" #######################\n",
" \n",
" rewrite_nodes = Expr[]\n",
" \n",
" \n",
" function need_rewrite!(gg)\n",
" gg==:_ #My parent is a rewrite candiated if I am a blank node\n",
" end\n",
" \n",
" function need_rewrite!(gg::Expr, top=false)\n",
" at_peak = ((top && !low_prec_node(gg)) #Don't internally change within low_prec_node, even if at top\n",
" || high_prec_node(gg)) #Do internally change with nodes of precences to high to propergate upwards\n",
" \n",
" need_rewrite_at_parent = false\n",
" for child in gg.args\n",
" child_need_rewrite = need_rewrite!(child)\n",
" this_child_demand_granparent_rewrite = child_need_rewrite && ((at_peak && child==:_) || !at_peak)\n",
" if this_child_demand_granparent_rewrite\n",
" need_rewrite_at_parent=true\n",
" break\n",
" end\n",
" end\n",
" \n",
" if need_rewrite_at_parent \n",
" return true\n",
" end\n",
" \n",
" #I can be rewritten as I am not demanding my parents be rewritten\n",
" for ii in 1:length(gg.args)\n",
" child = gg.args[ii]\n",
" child_need_rewrite = need_rewrite!(child)\n",
" if child_need_rewrite && at_peak\n",
" gg.args[ii]=terse_treechange(child)\n",
" end\n",
" end\n",
" \n",
" return false\n",
" end\n",
" \n",
" rewrite_top = need_rewrite!(ff,true)\n",
" #println(rewrite_top)\n",
" if rewrite_top\n",
" terse_treechange(ff)\n",
" else\n",
" ff\n",
" end\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"macro terse(ff)\n",
" terse!(ff)\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"#Failing,\n",
"#I'm not sure this failure is not infact the prefered behavour\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xxt1->if xxt1\n",
" \"true\"\n",
" else \n",
" \"false\"\n",
" end)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(_ ? \"true\" : \"false\") |> terse! #→ (x -> x) ? \"true\" : \"false\")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xxt1,xxt2)->if xxt1\n",
" xxt2\n",
" else \n",
" 0\n",
" end)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(_ ? _ : 0) |> terse! #→ (x -> x) ? (y -> y) : 0"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"#Failing, Can't Fix\n",
"#As (_) is interpretted as the same as _"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xxt2->map(xxt2,v))"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\n",
":(map((_), v)) |> terse! #→ map(x -> x, v) "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"#Won't Fix\n",
"#Only standalone _ are broken, iuf they form part of even a simple expression eg `1_` they work\n",
"#code only expressions are being rewritten, not symbols"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":_"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(_)|>terse! #→ x -> x \n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xxt2->f = xxt2)"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(f = _)|>terse! #→ f = x -> x\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"#Passing"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(map((xxt2->xxt2 + 2),v))"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(map(_ + 2, v) ))"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xxt2->xxt2 + 2)"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(_ + 2))"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(f = (xxt2->xxt2 + 2))"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(f=_+2) )"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(x->(xx2t2->begin # In[18], line 1:\n",
" xx2t2 + 2\n",
" end))"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(x->_+2) )"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(map((xxt2->xxt2 + 2),v))"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(map(_ + 2, v) ))"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xxt2->f(xxt2,b))"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(f(_,b)))"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xxt3->f(a,xxt3))"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(f(a,_)))"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xxt2,xxt3)->f(xxt2,xxt3))"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(f(_,_)))"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xx3t2->2 * xx3t2 ^ 2)"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(2_^2))"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xx3t2,xx3t3)->2 * xx3t2 ^ xx3t3)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(2_^_))"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(map((xx2t3->2xx2t3 + 2),v))"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(map(2_ + 2, v))) "
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xxt3->map(abs,xxt3))"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(map(abs,_)))"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xx2b2t3,xxt3)->map(2xx2b2t3 + 2,xxt3))"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(map(2_ + 2, _))) "
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xxt2->a[xxt2])"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(a[_]))"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xxt2,xxt3)->a[xxt2,xxt3])"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(a[_,_]))"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xxt2,xx3t3)->a[xxt2,1xx3t3])"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terse!(:(a[_,1_]))"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xxt2,xx3t3)->f(xxt2,2xx3t3))"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(f(_,2_)) |> terse!"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xx2b2t3,xxt3)->map(2xx2b2t3 + 2,xxt3))"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(map(2_ + 2, _)) |> terse! #→ x -> map(y -> 2y + 2, x)\n"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(map(((xx2t3,xxt3)->2xx2t3 - xxt3),v,w))"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(map(2_ - _, v, w)) |> terse! #→ map((x, y) -> 2x - y, v, w)\n"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xx2b2t3,xx2t3,xxt4)->map(2xx2b2t3 - xx2t3,v,xxt4))"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(map(2_ - _, v, _)) |> terse! #→ x -> map((y, z) -> 2y - z, v, x)\n"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xx2b2t3,xx2t3,xxt3,xxt4)->map(2xx2b2t3 - xx2t3,xxt3,xxt4))"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(map(2_ - _, _, _)) |> terse! #→ (x, y) -> map((z, w) -> 2z - w, x, y) "
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xxt2->map(xxt2,v))"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(map(_, v))|>terse! #→ x -> map(x, v)\n"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(f = (xxt3->2xxt3))"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(f = 2_)|>terse! #→ f = x -> 2x\n"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(x->(xx2t3->begin # In[38], line 1:\n",
" x ^ xx2t3\n",
" end))"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(x -> x^_)|>terse! #→ x -> y -> x^y\n"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xxt1,xxt2)->xxt1 && xxt2)"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(_ && _)|>terse! #→ (x, y) -> x && y\n"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":((xx1t2,xxt2)->!xx1t2 && xxt2)"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(!_ && _)|>terse! #→ (x, y) -> !x && y "
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xx3t2->2 * v[xx3t2])"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(2v[_])|> terse! #→ x -> 2v[x] (good)"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
":(xx3t2->2 * f(xx3t2))"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
":(2f(_)) |> terse! #→ 2*(x -> f(x)) (not so good)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 0.5.0-dev",
"language": "julia",
"name": "julia-0.5"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "0.5.0"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment