galaaz 0.4.9 → 0.4.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +798 -285
  3. data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +3 -12
  4. data/blogs/galaaz_ggplot/galaaz_ggplot.aux +5 -7
  5. data/blogs/galaaz_ggplot/galaaz_ggplot.html +69 -29
  6. data/blogs/galaaz_ggplot/galaaz_ggplot.pdf +0 -0
  7. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png +0 -0
  8. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png +0 -0
  9. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-latex/midwest_rb.pdf +0 -0
  10. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-latex/scatter_plot_rb.pdf +0 -0
  11. data/blogs/galaaz_ggplot/midwest.Rmd +1 -9
  12. data/blogs/gknit/gknit.Rmd +37 -40
  13. data/blogs/gknit/gknit.html +32 -30
  14. data/blogs/gknit/gknit.md +36 -37
  15. data/blogs/gknit/gknit.pdf +0 -0
  16. data/blogs/gknit/gknit.tex +35 -37
  17. data/blogs/manual/manual.Rmd +548 -125
  18. data/blogs/manual/manual.html +509 -286
  19. data/blogs/manual/manual.md +798 -285
  20. data/blogs/manual/manual.pdf +0 -0
  21. data/blogs/manual/manual.tex +2816 -0
  22. data/blogs/manual/manual_files/figure-latex/diverging_bar.pdf +0 -0
  23. data/blogs/nse_dplyr/nse_dplyr.Rmd +240 -74
  24. data/blogs/nse_dplyr/nse_dplyr.html +191 -87
  25. data/blogs/nse_dplyr/nse_dplyr.md +361 -107
  26. data/blogs/nse_dplyr/nse_dplyr.pdf +0 -0
  27. data/blogs/nse_dplyr/nse_dplyr.tex +1373 -0
  28. data/blogs/ruby_plot/ruby_plot.Rmd +61 -81
  29. data/blogs/ruby_plot/ruby_plot.html +54 -57
  30. data/blogs/ruby_plot/ruby_plot.md +48 -67
  31. data/blogs/ruby_plot/ruby_plot.pdf +0 -0
  32. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
  33. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
  34. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
  35. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
  36. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
  37. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
  38. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
  39. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
  40. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
  41. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
  42. data/blogs/ruby_plot/ruby_plot_files/figure-latex/dose_len.png +0 -0
  43. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
  44. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
  45. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
  46. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
  47. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
  48. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
  49. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
  50. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
  51. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
  52. data/blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
  53. data/lib/R_interface/rdata_frame.rb +0 -12
  54. data/lib/R_interface/robject.rb +14 -14
  55. data/lib/R_interface/ruby_extensions.rb +3 -31
  56. data/lib/R_interface/rvector.rb +0 -12
  57. data/lib/gknit/knitr_engine.rb +5 -3
  58. data/lib/util/exec_ruby.rb +22 -61
  59. data/specs/tmp.rb +26 -12
  60. data/version.rb +1 -1
  61. metadata +22 -17
  62. data/bin/gknit_old_r +0 -236
  63. data/blogs/dev/dev.Rmd +0 -23
  64. data/blogs/dev/dev.md +0 -58
  65. data/blogs/dev/dev2.Rmd +0 -65
  66. data/blogs/dev/model.rb +0 -41
  67. data/blogs/dplyr/dplyr.Rmd +0 -29
  68. data/blogs/dplyr/dplyr.html +0 -433
  69. data/blogs/dplyr/dplyr.md +0 -58
  70. data/blogs/dplyr/dplyr.rb +0 -63
  71. data/blogs/galaaz_ggplot/galaaz_ggplot.log +0 -640
  72. data/blogs/galaaz_ggplot/galaaz_ggplot.md +0 -431
  73. data/blogs/galaaz_ggplot/galaaz_ggplot.tex +0 -481
  74. data/blogs/galaaz_ggplot/midwest.png +0 -0
  75. data/blogs/galaaz_ggplot/scatter_plot.png +0 -0
  76. data/blogs/ruby_plot/ruby_plot.tex +0 -1077
@@ -12,6 +12,7 @@
12
12
  <meta name="author" content="Rodrigo Botafogo" />
13
13
  <meta name="author" content="Daniel Mossé - University of Pittsburgh" />
14
14
 
15
+ <meta name="date" content="2019-10-05" />
15
16
 
16
17
  <title>Non Standard Evaluation in dplyr with Galaaz</title>
17
18
 
@@ -373,18 +374,20 @@ $(document).ready(function () {
373
374
  <h1 class="title toc-ignore">Non Standard Evaluation in dplyr with Galaaz</h1>
374
375
  <h4 class="author"><em>Rodrigo Botafogo</em></h4>
375
376
  <h4 class="author"><em>Daniel Mossé - University of Pittsburgh</em></h4>
376
- <h4 class="date"><em>20/02/2019</em></h4>
377
+ <h4 class="date"><em>10/05/2019</em></h4>
377
378
 
378
379
  </div>
379
380
 
380
381
 
381
382
  <div id="introduction" class="section level1">
382
383
  <h1>Introduction</h1>
383
- <p>In this post we will see how to program with dplyr in Galaaz.</p>
384
- <div id="but-first-what-is-galaaz" class="section level3">
385
- <h3>But first, what is Galaaz??</h3>
386
- <p>Galaaz is a system for tightly coupling Ruby and R. Ruby is a powerful language, with a large community, a very large set of libraries and great for web development. However, it lacks libraries for data science, statistics, scientific plotting and machine learning. On the other hand, R is considered one of the most powerful languages for solving all of the above problems. Maybe the strongest competitor to R is Python with libraries such as NumPy, Panda, SciPy, SciKit-Learn and a couple more.</p>
387
- <p>With Galaaz we do not intend to re-implement any of the scientific libraries in R. However, we allow for very tight coupling between the two languages to the point that the Ruby developer does not need to know that there is an R engine running. For this to happen we use new technologies provided by Oracle: GraalVM, TruffleRuby and FastR:</p>
384
+ <p>In this post we will see how to program with <em>dplyr</em> in Galaaz.</p>
385
+ <div id="but-first-what-is-galaaz" class="section level2">
386
+ <h2>But first, what is Galaaz??</h2>
387
+ <p>Galaaz is a system for tightly coupling Ruby and R. Ruby is a powerful language, with a large community, a very large set of libraries and great for web development. However, it lacks libraries for data science, statistics, scientific plotting and machine learning. On the other hand, R is considered one of the most powerful languages for solving all of the above problems. Maybe the strongest competitor to R is Python with libraries such as NumPy, Pandas, SciPy, SciKit-Learn and many more.</p>
388
+ <p>With Galaaz we do not intend to re-implement any of the scientific libraries in R. However, we allow for very tight coupling between the two languages to the point that the Ruby developer does not need to know that there is an R engine running. Also, from the point of view of the R user/developer Galaaz looks a lot like R, with just minor syntactic difference, so there is almost no learning courve for the R developer. And as we will see in this post, programming with <em>dplyr</em> is easier in Galaaz than in R.</p>
389
+ <p>R users are probably quite knowledgeable about <em>dplyr</em>, for the Ruby developer, <em>dplyr</em> and the <em>tidyverse</em> libraries are a set of libraries for data manipulation in R, developed by Hardley Wickham, chief scientis at RStudio and a prolific R coder and writer.</p>
390
+ <p>For the coupling of Ruby and R we use new technologies provided by Oracle: GraalVM, TruffleRuby and FastR:</p>
388
391
  <pre><code> GraalVM is a universal virtual machine for running applications
389
392
  written in JavaScript, Python 3, Ruby, R, JVM-based languages like Java,
390
393
  Scala, Kotlin, and LLVM-based languages such as C and C++.
@@ -417,16 +420,21 @@ for the task at hand without making compromises.</code></pre>
417
420
  <li><a href="https://github.com/oracle/truffleruby">TruffleRuby</a></li>
418
421
  <li><a href="https://github.com/oracle/fastr">FastR</a></li>
419
422
  <li><a href="https://medium.com/graalvm/faster-r-with-fastr-4b8db0e0dceb">Faster R with FastR</a></li>
423
+ <li><a href="https://medium.freecodecamp.org/how-to-make-beautiful-ruby-plots-with-galaaz-320848058857">How to make Beautiful Ruby Plots with Galaaz</a></li>
424
+ <li><a href="https://towardsdatascience.com/ruby-plotting-with-galaaz-an-example-of-tightly-coupling-ruby-and-r-in-graalvm-520b69e21021">Ruby Plotting with Galaaz: An example of tightly coupling Ruby and R in GraalVM</a></li>
425
+ <li><a href="https://towardsdatascience.com/how-to-do-reproducible-research-in-ruby-with-gknit-c26d2684d64e">How to do reproducible research in Ruby with gKnit</a></li>
426
+ <li><a href="https://r4ds.had.co.nz/">R for Data Science</a></li>
427
+ <li><a href="https://adv-r.hadley.nz/">Advanced R</a></li>
420
428
  </ul>
421
429
  </div>
422
- <div id="now-to-programming-with-dplyr" class="section level3">
423
- <h3>Now to programming with dplyr</h3>
424
- <p>According to Hardley (<a href="https://dplyr.tidyverse.org/articles/programming.html" class="uri">https://dplyr.tidyverse.org/articles/programming.html</a>)</p>
430
+ <div id="programming-with-dplyr" class="section level2">
431
+ <h2>Programming with dplyr</h2>
432
+ <p>This post will follow closely the work done in <a href="https://dplyr.tidyverse.org/articles/programming.html" class="uri">https://dplyr.tidyverse.org/articles/programming.html</a>, by Hardley Wickham. In it, Hardley states:</p>
425
433
  <blockquote>
426
434
  <p>Most dplyr functions use non-standard evaluation (NSE). This is a catch-all term that means they don’t follow the usual R rules of evaluation. Instead, they capture the expression that you typed and evaluate it in a custom way. This has two main benefits for dplyr code:</p>
427
435
  </blockquote>
428
436
  <blockquote>
429
- <p>Operations on data frames can be expressed succinctly because you don’t need to repeat the name of the data frame. For example, you can write filter(df, x == 1, y == 2, z == 3) instead of df[df<span class="math inline">\(x == 1 &amp; df\)</span>y ==2 &amp; df$z == 3, ].</p>
437
+ <p>Operations on data frames can be expressed succinctly because you don’t need to repeat the name of the data frame. For example, you can write filter(df, x == 1, y == 2, z == 3) instead of df[df$x == 1 &amp; df$y ==2 &amp; df$z == 3, ].</p>
430
438
  </blockquote>
431
439
  <blockquote>
432
440
  <p>dplyr can choose to compute results in a different way to base R. This is important for database backends because dplyr itself doesn’t do any work, but instead generates the SQL that tells the database what to do.</p>
@@ -438,15 +446,8 @@ for the task at hand without making compromises.</code></pre>
438
446
  <p>Most dplyr arguments are not referentially transparent. That means you can’t replace a value with a seemingly equivalent object that you’ve defined elsewhere. In other words, this code:</p>
439
447
  </blockquote>
440
448
  <pre class="r"><code>df &lt;- data.frame(x = 1:3, y = 3:1)
441
- print(df)</code></pre>
442
- <pre><code>## x y
443
- ## 1 1 3
444
- ## 2 2 2
445
- ## 3 3 1</code></pre>
446
- <pre class="r"><code>print(filter(df, x == 1))</code></pre>
447
- <pre><code>## x y
448
- ## 1 1 3</code></pre>
449
- <pre class="r"><code>#&gt; # A tibble: 1 x 2
449
+ print(filter(df, x == 1))
450
+ #&gt; # A tibble: 1 x 2
450
451
  #&gt; x y
451
452
  #&gt; &lt;int&gt; &lt;int&gt;
452
453
  #&gt; 1 1 3</code></pre>
@@ -460,30 +461,39 @@ filter(df, my_var == 1)
460
461
  <blockquote>
461
462
  <p>This makes it hard to create functions with arguments that change how dplyr verbs are computed.</p>
462
463
  </blockquote>
464
+ <p>In this post we will see that programming with <em>dplyr</em> in Galaaz does not require knowledge of non-standard evaluation in R and can be accomplished by utilizing normal Ruby constructs.</p>
463
465
  </div>
464
466
  </div>
465
467
  <div id="writing-expressions-in-galaaz" class="section level1">
466
468
  <h1>Writing Expressions in Galaaz</h1>
467
- <p>Galaaz extends Ruby to work with complex expressions, similar to R’s expressions build with ‘quote’ (base R) or ‘quo’ (tidyverse). Let’s take a look at some of those expressions.</p>
469
+ <p>Galaaz extends Ruby to work with expressions, similar to R’s expressions build with ‘quote’ (base R) or ‘quo’ (tidyverse). Expressions in this context are like mathematical expressions or formulae. For instance, in mathematics, the expression <span class="math inline">\(y = sin(x)\)</span> describes a function but cannot be computed unless the value of <span class="math inline">\(x\)</span> is bound to some value.</p>
470
+ <p>Let’s take a look at some of those expressions in Ruby:</p>
468
471
  <div id="expressions-from-operators" class="section level2">
469
472
  <h2>Expressions from operators</h2>
470
- <p>The code bellow creates an expression summing two symbols</p>
473
+ <p>The code bellow creates an expression summing two symbols. Note that :a and :b are Ruby symbols and are not bound to any value at the time of expression definition:</p>
471
474
  <pre class="ruby"><code>exp1 = :a + :b
472
475
  puts exp1</code></pre>
473
476
  <pre><code>## a + b</code></pre>
474
- <p>We can build any complex mathematical expression</p>
477
+ <p>We can build any complex mathematical expression such as:</p>
475
478
  <pre class="ruby"><code>exp2 = (:a + :b) * 2.0 + :c ** 2 / :z
476
479
  puts exp2</code></pre>
477
480
  <pre><code>## (a + b) * 2 + c^2L/z</code></pre>
478
- <p>It is also possible to use inequality operators in building expressions</p>
481
+ <p>The ‘L’ after two indicates that 2 is an integer.</p>
482
+ <p>It is also possible to use inequality operators in building expressions:</p>
479
483
  <pre class="ruby"><code>exp3 = (:a + :b) &gt;= :z
480
484
  puts exp3</code></pre>
481
485
  <pre><code>## a + b &gt;= z</code></pre>
486
+ <p>Expressions’ definition can also make use of normal Ruby variables without any problem:</p>
487
+ <pre class="ruby"><code>x = 20
488
+ y = 30
489
+ exp_var = (:a + :b) * x &lt;= :z - y
490
+ puts exp_var</code></pre>
491
+ <pre><code>## (a + b) * 20L &lt;= z - 30L</code></pre>
482
492
  <p>Galaaz provides both symbolic representations for operators, such as (&gt;, &lt;, !=) as functional notation for those operators such as (.gt, .ge, etc.). So the same expression written above can also be written as</p>
483
493
  <pre class="ruby"><code>exp4 = (:a + :b).ge :z
484
494
  puts exp4</code></pre>
485
495
  <pre><code>## a + b &gt;= z</code></pre>
486
- <p>Two type of expression can only be created with the functional representation of the operators, those are expressions involving ‘==’, and ‘=’. In order to write an expression involving ‘==’ we need to use the method ‘.eq’ and for ‘=’ we need the function ‘.assign’</p>
496
+ <p>Two type of expression, however, can only be created with the functional representation of the operators, those are expressions involving ‘==’, and ‘=’. In order to write an expression involving ‘==’ we need to use the method ‘.eq’ and for ‘=’ we need the function ‘.assign’</p>
487
497
  <pre class="ruby"><code>exp5 = (:a + :b).eq :z
488
498
  puts exp5</code></pre>
489
499
  <pre><code>## a + b == z</code></pre>
@@ -497,43 +507,94 @@ puts exp_wrong</code></pre>
497
507
  ## Error in function (x, y, num.eq = TRUE, single.NA = TRUE, attrib.as.set = TRUE, :
498
508
  ## object 'a' not found (RError)
499
509
  ## Translated to internal error</code></pre>
500
- <p>and it might be difficult to understand what is going on here. The problem lies with the fact that when using ‘==’ we are comparing expression (:a + :b) to expression :z with ‘==’. When the comparison is executed, the system tries to evaluate :a, :b and :z, and those symbols, at this time are not bound to anything and we get a “object ‘a’ not found” message.<br />
501
- If we only use functional notation, this type of error will never occur.</p>
510
+ <p>and it might be difficult to understand what is going on here. The problem lies with the fact that when using ‘==’ we are comparing expression (:a + :b) to expression :z with ‘==’. When the comparison is executed, the system tries to evaluate :a, :b and :z, and those symbols at this time are not bound to anything and we get a “object ‘a’ not found” message. If we only use functional notation, this type of error will not occur.</p>
502
511
  </div>
503
512
  <div id="expressions-with-r-methods" class="section level2">
504
513
  <h2>Expressions with R methods</h2>
505
- <p>It is often necessary to create an expression that uses a method or function. For instance, in mathematics, it’s quite natural to write an expressin such as <span class="math inline">\(y = sin(x)\)</span>. In this case, the ‘sin’ function is part of the expression and should not immediately executed. Now, let’s say that ‘x’ is an angle of 45<span class="math inline">\(^\circ\)</span> and we acttually want our expression to be <span class="math inline">\(y = 0.850...\)</span>. When we want the function to be part of the expression, we call the function preceeding it by the letter E, such as ‘E.sin(x)’</p>
514
+ <p>It is often necessary to create an expression that uses a method or function. For instance, in mathematics, it’s quite natural to write an expressin such as <span class="math inline">\(y = sin(x)\)</span>. In this case, the ‘sin’ function is part of the expression and should not immediately be executed. When we want the function to be part of the expression, we call the function preceeding it by the letter E, such as ‘E.sin(x)’</p>
506
515
  <pre class="ruby"><code>exp7 = :y.assign E.sin(:x)
507
516
  puts exp7</code></pre>
508
517
  <pre><code>## y &lt;- sin(x)</code></pre>
509
- <p>However, if we want the function to be evaluated, then we use the normal call to function with R as ‘R.sin(x)’.</p>
510
- <pre class="ruby"><code>x = 45
511
- exp8 = :y.assign R.sin(x)
518
+ <p>Expressions can also be written using ‘.’ notation:</p>
519
+ <pre class="ruby"><code>exp8 = :y.assign :x.sin
512
520
  puts exp8</code></pre>
513
- <pre><code>## y &lt;- 0.850903524534118</code></pre>
521
+ <pre><code>## y &lt;- sin(x)</code></pre>
522
+ <p>When a function has multiple arguments, the first one can be used before the ‘.’:</p>
523
+ <pre class="ruby"><code>exp9 = :x.c(:y)
524
+ puts exp9</code></pre>
525
+ <pre><code>## c(x, y)</code></pre>
526
+ </div>
527
+ <div id="evaluating-an-expression" class="section level2">
528
+ <h2>Evaluating an Expression</h2>
529
+ <p>Expressions can be evaluated by calling function ‘eval’ with a binding. A binding can be provided with a list:</p>
530
+ <pre class="ruby"><code>exp = (:a + :b) * 2.0 + :c ** 2 / :z
531
+ puts exp.eval(R.list(a: 10, b: 20, c: 30, z: 40))</code></pre>
532
+ <pre><code>## [1] 82.5</code></pre>
533
+ <p>… with a data frame:</p>
534
+ <pre class="ruby"><code>df = R.data__frame(
535
+ a: R.c(1, 2, 3),
536
+ b: R.c(10, 20, 30),
537
+ c: R.c(100, 200, 300),
538
+ z: R.c(1000, 2000, 3000))
539
+
540
+ puts exp.eval(df)</code></pre>
541
+ <pre><code>## [1] 32 64 96</code></pre>
514
542
  </div>
515
543
  </div>
544
+ <div id="using-galaaz-to-call-r-functions" class="section level1">
545
+ <h1>Using Galaaz to call R functions</h1>
546
+ <p>Galaaz tries to emulate as closely as possible the way R functions are called and migrating from R to Galaaz should be quite easy requiring only minor syntactic changes to an R script. In this post, we do not have enough space to write a complete manual on Galaaz (a short manual can be found at: <a href="https://www.rubydoc.info/gems/galaaz/0.4.9" class="uri">https://www.rubydoc.info/gems/galaaz/0.4.9</a>), so we will present only a few examples scripts using Galaaz.</p>
547
+ <p>Basically, to call an R function from Ruby with Galaaz, one only needs to preceed the function with ‘R.’. For instance, to create a vector in R, the ‘c’ function is used. From Galaaz, a vector can be created by using ‘R.c’:</p>
548
+ <pre class="ruby"><code>vec = R.c(1.0, 2, 3)
549
+ puts vec</code></pre>
550
+ <pre><code>## [1] 1 2 3</code></pre>
551
+ <p>A list is created in R with the ‘list’ function, so in Galaaz we do:</p>
552
+ <pre class="ruby"><code>list = R.list(a: 1.0, b: 2, c: 3)
553
+ puts list</code></pre>
554
+ <pre><code>## $a
555
+ ## [1] 1
556
+ ##
557
+ ## $b
558
+ ## [1] 2
559
+ ##
560
+ ## $c
561
+ ## [1] 3</code></pre>
562
+ <p>Note that we can use named arguments in our list. The same code in R would be:</p>
563
+ <pre class="r"><code>lst = list(a = 1, b = 2L, c = 3L)
564
+ print(lst)</code></pre>
565
+ <pre><code>## $a
566
+ ## [1] 1
567
+ ##
568
+ ## $b
569
+ ## [1] 2
570
+ ##
571
+ ## $c
572
+ ## [1] 3</code></pre>
573
+ <p>Now, let’s say that ‘x’ is an angle of 45<span class="math inline">\(^\circ\)</span> and we acttually want to create the expression <span class="math inline">\(y = sin(45^\circ)\)</span>, which is <span class="math inline">\(y = 0.850...\)</span>. In this case, we will use ‘R.sin’:</p>
574
+ <pre class="ruby"><code>exp10 = :y.assign R.sin(45)
575
+ puts exp10</code></pre>
576
+ <pre><code>## y &lt;- 0.850903524534118</code></pre>
577
+ </div>
516
578
  <div id="filtering-using-expressions" class="section level1">
517
579
  <h1>Filtering using expressions</h1>
518
- <p>Now that we now how to write expression, we can use then to filter a data frame by expressions.<br />
519
- Let’s first start by creating a simple data frame with two columns named ‘x and y’</p>
520
- <pre class="ruby"><code>@df = R.data__frame(x: (1..3), y: (3..1))
521
- puts @df</code></pre>
580
+ <p>Now that we know how to write expression and call R functions let’s do some data manipulation in Galaaz. Let’s first start by creating the same data frame that we created previously in section “Programming with dplyr”:</p>
581
+ <pre class="ruby"><code>df = R.data__frame(x: (1..3), y: (3..1))
582
+ puts df</code></pre>
522
583
  <pre><code>## x y
523
584
  ## 1 1 3
524
585
  ## 2 2 2
525
586
  ## 3 3 1</code></pre>
526
- <p>In the code bellow we want to filter the data frame by rows in which the value of ‘x’ is equal to 1.</p>
527
- <pre class="ruby"><code>puts @df.filter(:x.eq 1)</code></pre>
587
+ <p>The ‘filter’ function can be called on this data frame either by using ‘R.filter(df, …)’ or by using dot notation. We prefer to use dot notation as shown bellow. The argument to ‘filter’ in Galaaz should be an expression. Note that if we gave to filter a Ruby expression such as ‘x == 1’, we would get an error, since there is no variable ‘x’ defined and if ‘x’ was a variable then ‘x == 1’ would either be ‘true’ or ‘false’. Our goal is to filter our data frame returning all rows in which the ‘x’ value is equal to 1. To express this we want: ‘:x.eq 1’, where :x will be interpreted by filter as the ‘x’ column.</p>
588
+ <pre class="ruby"><code>puts df.filter(:x.eq 1)</code></pre>
528
589
  <pre><code>## x y
529
590
  ## 1 1 3</code></pre>
530
- <p>In R, and when coding with ‘tidyverse’, arguments to a function are usually not <em>referencially transparent</em>. That is, ou can’t replace a value with a seemingly equivalent object that you’ve defined elsewhere. In other words, this code</p>
591
+ <p>In R, and when coding with ‘tidyverse’, arguments to a function are usually not <em>referencially transparent</em>. That is, you can’t replace a value with a seemingly equivalent object that you’ve defined elsewhere. In other words, this code</p>
531
592
  <pre class="r"><code>my_var &lt;- x
532
593
  filter(df, my_var == 1)</code></pre>
533
594
  <p>Generates the following error: &quot;object ‘x’ not found.</p>
534
- <p>However, in Ruby and Galaaz, arguments are referencially transparent as can be seen by the code bellow. Note, initally that ‘my_var = :x’ will not give the error “object ‘x’ not found” since ‘:x’ is treated as an expression and assigned to my_var. Then when doing (my_var.eq 1), my_var is a variable that resolves to ‘:x’ and it becomes equivalent to (:x.eq 1) which is what we want.</p>
595
+ <p>However, in Galaaz, arguments are referencially transparent as can be seen by the code bellow. Note initally that ‘my_var = :x’ will not give the error “object ‘x’ not found” since ‘:x’ is treated as an expression and assigned to my_var. Then when doing (my_var.eq 1), my_var is a variable that resolves to ‘:x’ and it becomes equivalent to (:x.eq 1) which is what we want.</p>
535
596
  <pre class="ruby"><code>my_var = :x
536
- puts @df.filter(my_var.eq 1)</code></pre>
597
+ puts df.filter(my_var.eq 1)</code></pre>
537
598
  <pre><code>## x y
538
599
  ## 1 1 3</code></pre>
539
600
  <p>As stated by Hardley</p>
@@ -544,34 +605,46 @@ puts @df.filter(my_var.eq 1)</code></pre>
544
605
  df[df$x == y, ]
545
606
  df[x == df$y, ]
546
607
  df[x == y, ]</code></pre>
547
- <p>In galaaz this ambiguity does not exist, filter(df, x.eq y) is not a valid expression as expressions are build with symbols. In doing filter(df, :x.eq y) we are looking for elements of the ‘x’ column that are equal to a previously defined y variable. Finally, filter(df, :x.eq :y) we are looking for elements in which the ‘x’ column value is equal to the ‘y’ column value. This can be seen in the following two chunks of code:</p>
548
- <pre class="ruby"><code>@y = 1
549
- @x = 2
608
+ <p>In galaaz this ambiguity does not exist, filter(df, x.eq y) is not a valid expression as expressions are build with symbols. In doing filter(df, :x.eq y) we are looking for elements of the ‘x’ column that are equal to a previously defined y variable. Finally in filter(df, :x.eq :y) we are looking for elements in which the ‘x’ column value is equal to the ‘y’ column value. This can be seen in the following two chunks of code:</p>
609
+ <pre class="ruby"><code>y = 1
610
+ x = 2
550
611
 
551
612
  # looking for values where the 'x' column is equal to the 'y' column
552
- puts @df.filter(:x.eq :y)</code></pre>
613
+ puts df.filter(:x.eq :y)</code></pre>
553
614
  <pre><code>## x y
554
615
  ## 1 2 2</code></pre>
555
616
  <pre class="ruby"><code># looking for values where the 'x' column is equal to the 'y' variable
556
617
  # in this case, the number 1
557
- puts @df.filter(:x.eq @y)</code></pre>
618
+ puts df.filter(:x.eq y)</code></pre>
558
619
  <pre><code>## x y
559
620
  ## 1 1 3</code></pre>
560
621
  </div>
561
622
  <div id="writing-a-function-that-applies-to-different-data-sets" class="section level1">
562
623
  <h1>Writing a function that applies to different data sets</h1>
624
+ <p>Let’s suppose that we want to write a function that receives as the first argument a data frame and as second argument an expression that adds a column to the data frame that is equal to the sum of elements in column ‘a’ plus ‘x’.</p>
625
+ <p>Here is the intended behaviour using the ‘mutate’ function of ‘dplyr’:</p>
563
626
  <pre><code>mutate(df1, y = a + x)
564
627
  mutate(df2, y = a + x)
565
628
  mutate(df3, y = a + x)
566
629
  mutate(df4, y = a + x)</code></pre>
567
- <p>Here we create a mutate_y Ruby method.</p>
630
+ <p>The naive approach to writing an R function to solve this problem is:</p>
631
+ <pre><code>mutate_y &lt;- function(df) {
632
+ mutate(df, y = a + x)
633
+ }</code></pre>
634
+ <p>Unfortunately, in R, this function can fail silently if one of the variables isn’t present in the data frame, but is present in the global environment. We will not go through here how to solve this problem in R.</p>
635
+ <p>In Galaaz the method mutate_y bellow will work fine and will never fail silently.</p>
568
636
  <pre class="ruby"><code>def mutate_y(df)
569
637
  df.mutate(:y.assign :a + :x)
570
638
  end</code></pre>
571
- <p>Note that contrary to what happens in R, method mutate_y will fail independetly from the fact that variable a’ is defined or not.</p>
639
+ <p>Here we create a data frame that has only one column namedx’:</p>
572
640
  <pre class="ruby"><code>df1 = R.data__frame(x: (1..3))
573
- puts df1
574
- a = 10
641
+ puts df1</code></pre>
642
+ <pre><code>## x
643
+ ## 1 1
644
+ ## 2 2
645
+ ## 3 3</code></pre>
646
+ <p>Note that method mutate_y will fail independetly from the fact that variable ‘a’ is defined and in the scope of the method. Variable ‘a’ has no relationship with the symbol ‘:a’ used in the definition of ‘mutate_y’ above:</p>
647
+ <pre class="ruby"><code>a = 10
575
648
  mutate_y(df1)</code></pre>
576
649
  <pre><code>## Message:
577
650
  ## Error in mutate_impl(.data, dots) :
@@ -583,14 +656,24 @@ mutate_y(df1)</code></pre>
583
656
  </div>
584
657
  <div id="different-expressions" class="section level1">
585
658
  <h1>Different expressions</h1>
586
- <pre class="r"><code>df &lt;- data.frame(
659
+ <p>Let’s move to the next problem as presented by Hardley where trying to write a function in R that will receive two argumens, the first a variable and the second an expression is not trivial. Bellow we create a data frame and we want to write a function that groups data by a variable and summarises it by an expression:</p>
660
+ <pre class="r"><code>set.seed(123)
661
+
662
+ df &lt;- data.frame(
587
663
  g1 = c(1, 1, 2, 2, 2),
588
664
  g2 = c(1, 2, 1, 2, 1),
589
665
  a = sample(5),
590
666
  b = sample(5)
591
667
  )
592
668
 
593
- d2 &lt;- df %&gt;%
669
+ as.data.frame(df) </code></pre>
670
+ <pre><code>## g1 g2 a b
671
+ ## 1 1 1 2 1
672
+ ## 2 1 2 4 3
673
+ ## 3 2 1 5 4
674
+ ## 4 2 2 3 2
675
+ ## 5 2 1 1 5</code></pre>
676
+ <pre class="r"><code>d2 &lt;- df %&gt;%
594
677
  group_by(g1) %&gt;%
595
678
  summarise(a = mean(a))
596
679
 
@@ -604,9 +687,9 @@ as.data.frame(d2) </code></pre>
604
687
 
605
688
  as.data.frame(d2) </code></pre>
606
689
  <pre><code>## g2 a
607
- ## 1 1 3.666667
608
- ## 2 2 2.000000</code></pre>
609
- <p>Trying to write a function in R that will receive two argumens, the first a variable and the second an expression is not trivia. As shown by Hardley, one might expect this function to do the trick:</p>
690
+ ## 1 1 2.666667
691
+ ## 2 2 3.500000</code></pre>
692
+ <p>As shown by Hardley, one might expect this function to do the trick:</p>
610
693
  <pre class="r"><code>my_summarise &lt;- function(df, group_var) {
611
694
  df %&gt;%
612
695
  group_by(group_var) %&gt;%
@@ -615,37 +698,37 @@ as.data.frame(d2) </code></pre>
615
698
 
616
699
  # my_summarise(df, g1)
617
700
  #&gt; Error: Column `group_var` is unknown</code></pre>
618
- <p>In order to solve this problem, coding with dplyr requires the introduction of many new concepts and functions such as ‘quo’, ‘quos’, ‘enquo’, ‘enquos’, ‘!!’ (bang bang), ‘!!!’ (triple bang).</p>
619
- <p>Now, let’s try to implement the same function in galaaz. The next code block first prints the ‘df’ data frame define previously in R, then creates the my_summarize function and calls it passing the R data frame and the group by variable ‘:g1’</p>
701
+ <p>In order to solve this problem, coding with dplyr requires the introduction of many new concepts and functions such as ‘quo’, ‘quos’, ‘enquo’, ‘enquos’, ‘!!’ (bang bang), ‘!!!’ (triple bang). Again, we’ll leave to Hardley the explanation on how to use all those functions.</p>
702
+ <p>Now, let’s try to implement the same function in galaaz. The next code block first prints the ‘df’ data frame define previously in R (to access an R variable from Galaaz, we use the tilda operator ‘~’ applied to the R variable name as symbol, i.e., ‘:df’. We then create the my_summarize method and call it passing the R data frame and the group by variable ‘:g1’:</p>
620
703
  <pre class="ruby"><code>puts ~:df
621
704
  print &quot;\n&quot;
622
705
 
623
706
  def my_summarize(df, group_var)
624
707
  df.group_by(group_var).
625
- summarize(a: E.mean(:a))
708
+ summarize(a: :a.mean)
626
709
  end
627
710
 
628
- puts my_summarize((~:df), :g1).as__data__frame</code></pre>
711
+ puts my_summarize(:df, :g1).as__data__frame</code></pre>
629
712
  <pre><code>## g1 g2 a b
630
- ## 1 1 1 5 2
631
- ## 2 1 2 1 5
632
- ## 3 2 1 2 4
633
- ## 4 2 2 3 1
634
- ## 5 2 1 4 3
713
+ ## 1 1 1 2 1
714
+ ## 2 1 2 4 3
715
+ ## 3 2 1 5 4
716
+ ## 4 2 2 3 2
717
+ ## 5 2 1 1 5
635
718
  ##
636
719
  ## g1 a
637
720
  ## 1 1 3
638
721
  ## 2 2 3</code></pre>
639
- <p>It works!!! Well let’s make sure this was not just some coincidence</p>
640
- <pre class="ruby"><code>puts my_summarize((~:df), :g2).as__data__frame</code></pre>
722
+ <p>It works!!! Well, let’s make sure this was not just some coincidence</p>
723
+ <pre class="ruby"><code>puts my_summarize(:df, :g2).as__data__frame</code></pre>
641
724
  <pre><code>## g2 a
642
- ## 1 1 3.666667
643
- ## 2 2 2.000000</code></pre>
725
+ ## 1 1 2.666667
726
+ ## 2 2 3.500000</code></pre>
644
727
  <p>Great, everything is fine! No magic, no new functions, no complexities, just normal, standard Ruby code. If you’ve ever done NSE in R, this certainly feels much safer and easy to implement.</p>
645
728
  </div>
646
729
  <div id="different-input-variables" class="section level1">
647
730
  <h1>Different input variables</h1>
648
- <p>In the previous section we’ve managed to get rid of all NSE formulation for a simple example, but does this remain true for more complex examples, or will the Ruby way prove inpractical for more complex code?</p>
731
+ <p>In the previous section we’ve managed to get rid of all NSE formulation for a simple example, but does this remain true for more complex examples, or will the Galaaz way prove inpractical for more complex code?</p>
649
732
  <p>In the next example Hardley proposes us to write a function that given an expression such as ‘a’ or ‘a * b’, calculates three summaries. What we want a function that does the same as these R statements:</p>
650
733
  <pre><code>summarise(df, mean = mean(a), sum = sum(a), n = n())
651
734
  #&gt; # A tibble: 1 x 3
@@ -657,7 +740,7 @@ summarise(df, mean = mean(a * b), sum = sum(a * b), n = n())
657
740
  #&gt; # A tibble: 1 x 3
658
741
  #&gt; mean sum n
659
742
  #&gt; &lt;dbl&gt; &lt;int&gt; &lt;int&gt;
660
- #&gt; 1 9.6 48 5</code></pre>
743
+ #&gt; 1 9 45 5</code></pre>
661
744
  <p>Let’s try it in galaaz:</p>
662
745
  <pre class="ruby"><code>def my_summarise2(df, expr)
663
746
  df.summarize(
@@ -672,8 +755,8 @@ puts my_summarise2((~:df), :a * :b)</code></pre>
672
755
  <pre><code>## mean sum n
673
756
  ## 1 3 15 5
674
757
  ## mean sum n
675
- ## 1 7.6 38 5</code></pre>
676
- <p>Once again, there is no need to use any special theory or functions. The only point to be careful about is the use of ‘E’ to build an expression that uses the mean, sum and n.</p>
758
+ ## 1 9 45 5</code></pre>
759
+ <p>Once again, there is no need to use any special theory or functions. The only point to be careful about is the use of ‘E’ to build expressions from functions mean’, sum and n’.</p>
677
760
  </div>
678
761
  <div id="different-input-and-output-variable" class="section level1">
679
762
  <h1>Different input and output variable</h1>
@@ -697,7 +780,8 @@ mutate(df, mean_b = mean(b), sum_b = sum(b))
697
780
  #&gt; 3 2 1 2 1 3 15
698
781
  #&gt; 4 2 2 5 4 3 15
699
782
  #&gt; # … with 1 more row</code></pre>
700
- <p>Here is our Ruby code</p>
783
+ <p>In order to solve this problem in R, Hardley needs to introduce some more new functions and notations: ‘quo_name’ and the ‘:=’ operator from package ‘rlang’</p>
784
+ <p>Here is our Ruby code:</p>
701
785
  <pre class="ruby"><code>def my_mutate(df, expr)
702
786
  mean_name = &quot;mean_#{expr.to_s}&quot;
703
787
  sum_name = &quot;sum_#{expr.to_s}&quot;
@@ -709,22 +793,24 @@ end
709
793
  puts my_mutate((~:df), :a)
710
794
  puts my_mutate((~:df), :b)</code></pre>
711
795
  <pre><code>## g1 g2 a b mean_a sum_a
712
- ## 1 1 1 5 2 3 15
713
- ## 2 1 2 1 5 3 15
714
- ## 3 2 1 2 4 3 15
715
- ## 4 2 2 3 1 3 15
716
- ## 5 2 1 4 3 3 15
796
+ ## 1 1 1 2 1 3 15
797
+ ## 2 1 2 4 3 3 15
798
+ ## 3 2 1 5 4 3 15
799
+ ## 4 2 2 3 2 3 15
800
+ ## 5 2 1 1 5 3 15
717
801
  ## g1 g2 a b mean_b sum_b
718
- ## 1 1 1 5 2 3 15
719
- ## 2 1 2 1 5 3 15
720
- ## 3 2 1 2 4 3 15
721
- ## 4 2 2 3 1 3 15
722
- ## 5 2 1 4 3 3 15</code></pre>
802
+ ## 1 1 1 2 1 3 15
803
+ ## 2 1 2 4 3 3 15
804
+ ## 3 2 1 5 4 3 15
805
+ ## 4 2 2 3 2 3 15
806
+ ## 5 2 1 1 5 3 15</code></pre>
723
807
  <p>It really seems that “Non Standard Evaluation” is actually quite standard in Galaaz! But, you might have noticed a small change in the way the arguments to the mutate method were called. In a previous example we used df.summarise(mean: E.mean(:a), …) where the column name was followed by a ‘:’ colom. In this example, we have df.mutate(mean_name =&gt; E.mean(expr), …) and variable mean_name is not followed by ‘:’ but by ‘=&gt;’. This is standard Ruby notation.</p>
724
808
  <p>[explain….]</p>
725
809
  </div>
726
810
  <div id="capturing-multiple-variables" class="section level1">
727
811
  <h1>Capturing multiple variables</h1>
812
+ <p>Moving on with new complexities, Hardley proposes us to solve the problem in which the summarise function will receive any number of grouping variables.</p>
813
+ <p>This again is quite standard Ruby. In order to receive an undefined number of paramenters the paramenter is preceded by ’*’:</p>
728
814
  <pre class="ruby"><code>def my_summarise3(df, *group_vars)
729
815
  df.group_by(*group_vars).
730
816
  summarise(a: E.mean(:a))
@@ -732,14 +818,26 @@ end
732
818
 
733
819
  puts my_summarise3((~:df), :g1, :g2).as__data__frame</code></pre>
734
820
  <pre><code>## g1 g2 a
735
- ## 1 1 1 5
736
- ## 2 1 2 1
821
+ ## 1 1 1 2
822
+ ## 2 1 2 4
737
823
  ## 3 2 1 3
738
824
  ## 4 2 2 3</code></pre>
739
825
  </div>
826
+ <div id="why-does-r-require-nse-and-galaaz-does-not" class="section level1">
827
+ <h1>Why does R require NSE and Galaaz does not?</h1>
828
+ <p>NSE introduces a number of new concepts, such as ‘quoting’, ‘quasiquotation’, ‘unquoting’ and ‘unquote-splicing’, while in Galaaz none of those concepts are needed. What gives?</p>
829
+ <p>R is an extremely flexible language and it has lazy evaluation of parameters. When in R a function is called as ‘summarise(df, a = b)’, the summarise function receives the litteral ‘a = b’ parameter and can work with this as if it were a string. In R, it is not clear what a and b are, they can be expressions or they can be variables, it is up to the function to decide what ‘a = b’ means.</p>
830
+ <p>In Ruby, there is no lazy evaluation of parameters and ‘a’ is always a variable and so is ‘b’. Variables assume their value as soon as they are used, so ‘x = a’ is immediately evaluate and variable ‘x’ will receive the value of variable ‘a’ as soon as the Ruby statement is executed. Ruby also provides the notion of a symbol; ‘:a’ is a symbol and does not evaluate to anything. Galaaz uses Ruby symbols to build expressions that are not bound to anything: ‘:a.eq :b’ is clearly an expression and has no relationship whatsoever with the statment ‘a = b’. By using symbols, variables and expressions all the possible ambiguities that are found in R are eliminated in Galaaz.</p>
831
+ <p>The main problem that remains, is that in R, functions are not clearly documented as what type of input they are expecting, they might be expecting regular variables or they might be expecting expressions and the R function will know how to deal with an input of the form ‘a = b’, now for the Ruby developer it might not be immediately clear if it should call the function passing the value ‘true’ if variable ‘a’ is equal to variable ‘b’ or if it should call the function passing the expression ‘:a.eq :b’.</p>
832
+ </div>
740
833
  <div id="advanced-dplyr-features" class="section level1">
741
834
  <h1>Advanced dplyr features</h1>
742
- <p><a href="https://www.r-bloggers.com/programming-with-dplyr-by-using-dplyr/" class="uri">https://www.r-bloggers.com/programming-with-dplyr-by-using-dplyr/</a></p>
835
+ <p>In the blog: Programming with dplyr by using dplyr (<a href="https://www.r-bloggers.com/programming-with-dplyr-by-using-dplyr/" class="uri">https://www.r-bloggers.com/programming-with-dplyr-by-using-dplyr/</a>) Iñaki Úcar shows surprise that some R users are trying to code in dplyr avoiding the use of NSE. For instance he says:</p>
836
+ <blockquote>
837
+ <p>Take the example of seplyr. It stands for standard evaluation dplyr, and enables us to program over dplyr without having “to bring in (or study) any deep-theory or heavy-weight tools such as rlang/tidyeval”.</p>
838
+ </blockquote>
839
+ <p>For me, there isn’t really any surprise that users are trying to avoid dplyr deep-theory. R users frequently are not programmers and learning to code is already hard business, on top of that, having to learn how to ‘quote’ or ‘enquo’ or ‘quos’ or ‘enquos’ is not necessarily a ‘piece of cake’. So much so, that ‘tidyeval’ has some more advanced functions that instead of using quoted expressions, uses strings as arguments.</p>
840
+ <p>In the following examples, we show the use of functions ‘group_by_at’, ‘summarise_at’ and ‘rename_at’ that receive strings as argument. The data frame used in ‘starwars’ that describes features of characters in the Starwars movies:</p>
743
841
  <pre class="ruby"><code>puts (~:starwars).head.as__data__frame</code></pre>
744
842
  <pre><code>## name height mass hair_color skin_color eye_color birth_year
745
843
  ## 1 Luke Skywalker 172 77 blond fair blue 19.0
@@ -769,6 +867,7 @@ puts my_summarise3((~:df), :g1, :g2).as__data__frame</code></pre>
769
867
  ## 4 TIE Advanced x1
770
868
  ## 5 Imperial Speeder Bike
771
869
  ## 6</code></pre>
870
+ <p>The grouped_mean function bellow will receive a grouping variable and calculate summaries for the value_variables given:</p>
772
871
  <pre class="r"><code>grouped_mean &lt;- function(data, grouping_variables, value_variables) {
773
872
  data %&gt;%
774
873
  group_by_at(grouping_variables) %&gt;%
@@ -797,15 +896,16 @@ as.data.frame(gm) </code></pre>
797
896
  ## 13 unknown 31.50000 NaN 3
798
897
  ## 14 white 48.00000 NaN 1
799
898
  ## 15 yellow 81.11111 76.38000 11</code></pre>
899
+ <p>The same code with Galaaz, becomes:</p>
800
900
  <pre class="ruby"><code>def grouped_mean(data, grouping_variables, value_variables)
801
901
  data.
802
902
  group_by_at(grouping_variables).
803
903
  mutate(count: E.n).
804
904
  summarise_at(E.c(value_variables, &quot;count&quot;), ~:mean, na__rm: true).
805
- rename_at(value_variables, R.funs(E.paste0(&quot;mean_&quot;, value_variables)))
905
+ rename_at(value_variables, E.funs(E.paste0(&quot;mean_&quot;, value_variables)))
806
906
  end
807
907
 
808
- puts grouped_mean((~:starwars), &quot;eye_color&quot;, R.c(&quot;mass&quot;, &quot;birth_year&quot;)).as__data__frame</code></pre>
908
+ puts grouped_mean((~:starwars), &quot;eye_color&quot;, E.c(&quot;mass&quot;, &quot;birth_year&quot;)).as__data__frame</code></pre>
809
909
  <pre><code>## eye_color mean_mass mean_birth_year count
810
910
  ## 1 black 76.28571 33.00000 10
811
911
  ## 2 blue 86.51667 67.06923 19
@@ -823,6 +923,10 @@ puts grouped_mean((~:starwars), &quot;eye_color&quot;, R.c(&quot;mass&quot;, &qu
823
923
  ## 14 white 48.00000 NaN 1
824
924
  ## 15 yellow 81.11111 76.38000 11</code></pre>
825
925
  </div>
926
+ <div id="conclusion" class="section level1">
927
+ <h1>Conclusion</h1>
928
+ <p>Ruby and Galaaz provide a nice framework for developing code that uses R functions. Although R is a very powerful and flexible language, sometimes, too much flexibility makes life harder for the casual user. We believe however, that even for the advanced user, Ruby integrated with R throught Galaaz, makes a powerful environment for data analysis. In this blog post we showed how Galaaz consistent syntax eliminates the need for complex constructs such as quoting, enquoting, quasiquotation, etc. This simplification comes from the fact that expressions and variables are clearly separated objects, which is not the case in the R language.</p>
929
+ </div>
826
930
 
827
931
 
828
932