Moving faster with REPL

Introduction to REPL

Developers like to “move fast and break things.” Well, we like to move fast anyway. A “REPL” is a tool I’ve found that prevents me from getting bogged down working within the context of a large application. Of course, at some point, my new feature or bugfix has to be integrated into the codebase, but starting there adds friction and slows me down. In this post, you’ll learn about what REPLs are, and how to use them to work efficiently.

A REPL is a Read-Evaluate-Print Loop. This concept was first introduced in the Lisp programming language, to allow quick experiments in Lisp. In Lisp, the following is an implementation of a basic REPL:

<span>(</span><span>loop</span> <span>(</span><span>print</span> <span>(</span><span>eval</span> <span>(</span><span>read</span><span>))))</span>
<span>(</span><span>loop</span> <span>(</span><span>print</span> <span>(</span><span>eval</span> <span>(</span><span>read</span><span>))))</span>
(loop (print (eval (read))))

Enter fullscreen mode Exit fullscreen mode

Reading the commands from the inside out (which is how they are executed in Lisp), you can see where REPL gets its name!

Generally speaking, you invoke a REPL from the command line. When you start up a REPL, it will take you to a new interface, similar to a command line, but your instructions are interpreted in the language of the REPL. In fact, you can think of a command prompt as a REPL for Bash. Once in a REPL, you can run commands, define variables, write functions, etc. and see the results.

Examples: Python and Node

Both Python and Node come with fairly sophisticated REPLs when you install them. Here are some examples you can try!

Python

Start up the Python REPL, by typing python3 at your command prompt (in this case, user@comp ~$) and pressing enter. It will print out some information on your python installation, and leave you at the REPL prompt (the >>>):

user@comp ~<span>$ </span>python3
Python 3.6.1 <span>(</span>default, Apr 4 2017, 09:36:47<span>)</span>
<span>[</span>GCC 4.2.1 Compatible Apple LLVM 7.0.2 <span>(</span>clang-700.1.81<span>)]</span> on darwin
Type <span>"help"</span>, <span>"copyright"</span>, <span>"credits"</span> or <span>"license"</span> <span>for </span>more information.
<span>>>></span>
user@comp ~<span>$ </span>python3
Python 3.6.1 <span>(</span>default, Apr  4 2017, 09:36:47<span>)</span> 
<span>[</span>GCC 4.2.1 Compatible Apple LLVM 7.0.2 <span>(</span>clang-700.1.81<span>)]</span> on darwin
Type <span>"help"</span>, <span>"copyright"</span>, <span>"credits"</span> or <span>"license"</span> <span>for </span>more information.
<span>>>></span>
user@comp ~$ python3 Python 3.6.1 (default, Apr 4 2017, 09:36:47) [GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>>

Enter fullscreen mode Exit fullscreen mode

From here, you can perform computations, define variables and functions, etc:

<span>>>></span> <span>1</span><span>+</span><span>1</span>
<span>2</span>
<span>>>></span> <span>greeting</span> <span>=</span> <span>'hello world'</span>
<span>>>></span> <span>print</span><span>(</span><span>greeting</span><span>)</span>
<span>hello</span> <span>world</span>
<span>>>></span> <span>def</span> <span>print_greeting</span><span>(</span><span>greeting</span><span>):</span>
<span>...</span> <span>print</span><span>(</span><span>greeting</span><span>)</span>
<span>...</span>
<span>>>></span> <span>print_greeting</span><span>(</span><span>'hello world'</span><span>)</span>
<span>hello</span> <span>world</span>
<span>>>></span> <span>print_greeting</span><span>(</span><span>'hello function'</span><span>)</span>
<span>hello</span> <span>function</span>
<span>>>></span> <span>1</span><span>+</span><span>1</span>
<span>2</span>
<span>>>></span> <span>greeting</span> <span>=</span> <span>'hello world'</span>
<span>>>></span> <span>print</span><span>(</span><span>greeting</span><span>)</span>
<span>hello</span> <span>world</span>
<span>>>></span> <span>def</span> <span>print_greeting</span><span>(</span><span>greeting</span><span>):</span>
<span>...</span>     <span>print</span><span>(</span><span>greeting</span><span>)</span>
<span>...</span> 
<span>>>></span> <span>print_greeting</span><span>(</span><span>'hello world'</span><span>)</span>
<span>hello</span> <span>world</span>
<span>>>></span> <span>print_greeting</span><span>(</span><span>'hello function'</span><span>)</span>
<span>hello</span> <span>function</span>
>>> 1+1 2 >>> greeting = 'hello world' >>> print(greeting) hello world >>> def print_greeting(greeting): ... print(greeting) ... >>> print_greeting('hello world') hello world >>> print_greeting('hello function') hello function

Enter fullscreen mode Exit fullscreen mode

Exit with ^d (ctrl+d)

<span>>>></span> ^d
user@comp ~<span>$</span>
<span>>>></span> ^d
user@comp ~<span>$</span>
>>> ^d user@comp ~$

Enter fullscreen mode Exit fullscreen mode

Node

Enter the Node REPL

user@comp ~<span>$ </span>node
<span>></span>
user@comp ~<span>$ </span>node
<span>></span> 
user@comp ~$ node >

Enter fullscreen mode Exit fullscreen mode

Just like in Python, you can perform computations, define variables and functions, etc:

<span>></span> <span>1</span><span>+</span><span>1</span>
<span>2</span>
<span>></span> <span>const</span> <span>greeting</span> <span>=</span> <span>'</span><span>hello world</span><span>'</span><span>;</span>
<span>undefined</span>
<span>></span> <span>console</span><span>.</span><span>log</span><span>(</span><span>greeting</span><span>);</span>
<span>hello</span> <span>world</span>
<span>undefined</span>
<span>></span> <span>const</span> <span>printGreeting</span> <span>=</span> <span>(</span><span>greeting</span><span>)</span> <span>=></span> <span>console</span><span>.</span><span>log</span><span>(</span><span>greeting</span><span>);</span>
<span>undefined</span>
<span>></span> <span>printGreeting</span><span>(</span><span>'</span><span>hello world</span><span>'</span><span>);</span>
<span>hello</span> <span>world</span>
<span>undefined</span>
<span>></span> <span>printGreeting</span><span>(</span><span>'</span><span>hello function</span><span>'</span><span>);</span>
<span>hello</span> <span>function</span>
<span>undefined</span>
<span>></span> <span>1</span><span>+</span><span>1</span>
<span>2</span>
<span>></span> <span>const</span> <span>greeting</span> <span>=</span> <span>'</span><span>hello world</span><span>'</span><span>;</span>
<span>undefined</span>
<span>></span> <span>console</span><span>.</span><span>log</span><span>(</span><span>greeting</span><span>);</span>
<span>hello</span> <span>world</span>
<span>undefined</span>
<span>></span> <span>const</span> <span>printGreeting</span> <span>=</span> <span>(</span><span>greeting</span><span>)</span> <span>=></span> <span>console</span><span>.</span><span>log</span><span>(</span><span>greeting</span><span>);</span>
<span>undefined</span>
<span>></span> <span>printGreeting</span><span>(</span><span>'</span><span>hello world</span><span>'</span><span>);</span>
<span>hello</span> <span>world</span>
<span>undefined</span>
<span>></span> <span>printGreeting</span><span>(</span><span>'</span><span>hello function</span><span>'</span><span>);</span>
<span>hello</span> <span>function</span>
<span>undefined</span>
> 1+1 2 > const greeting = 'hello world'; undefined > console.log(greeting); hello world undefined > const printGreeting = (greeting) => console.log(greeting); undefined > printGreeting('hello world'); hello world undefined > printGreeting('hello function'); hello function undefined

Enter fullscreen mode Exit fullscreen mode

Exit with ^d (ctrl+d)

<span>></span> ^d
user@comp ~<span>$</span>
<span>></span> ^d
user@comp ~<span>$</span>
> ^d user@comp ~$

Enter fullscreen mode Exit fullscreen mode

The undefined that crops up in the Node example is the return value of each statement. If your statement has a defined return value, that will be printed instead, as in the 1+1 example. Note also that these REPLs have command history, so you can press “up” to view past commands, even between sessions.

Implementation

The REPL is just like any program that you run from your command line. When you run it, it gives some output and then waits for user input. When a statement is entered, it evaluates the statement, and prints out the result. In both Python and Node, there are built-in modules that can provide a REPL with some injected “context”. You can read @rpalo ’s excellent post here for how to make use of the Python library Code to create your own REPL. Here’s how to do it in Node:

<span>// include the repl library</span>
<span>const</span> <span>repl</span> <span>=</span> <span>require</span><span>(</span><span>'</span><span>repl</span><span>'</span><span>);</span>
<span>// start it up, with the desired prompt string</span>
<span>const</span> <span>r</span> <span>=</span> <span>repl</span><span>.</span><span>start</span><span>(</span><span>'</span><span>> </span><span>'</span><span>);</span>
<span>// inject a couple pieces of context</span>
<span>r</span><span>.</span><span>context</span><span>.</span><span>text</span> <span>=</span> <span>'</span><span>This is some text</span><span>'</span><span>;</span>
<span>r</span><span>.</span><span>context</span><span>.</span><span>greet</span> <span>=</span> <span>(</span><span>name</span><span>)</span> <span>=></span> <span>console</span><span>.</span><span>log</span><span>(</span><span>`hello </span><span>${</span><span>name</span><span>}</span><span>`</span><span>);</span>
<span>// include the repl library</span>
<span>const</span> <span>repl</span> <span>=</span> <span>require</span><span>(</span><span>'</span><span>repl</span><span>'</span><span>);</span>

<span>// start it up, with the desired prompt string</span>
<span>const</span> <span>r</span> <span>=</span> <span>repl</span><span>.</span><span>start</span><span>(</span><span>'</span><span>> </span><span>'</span><span>);</span>

<span>// inject a couple pieces of context</span>
<span>r</span><span>.</span><span>context</span><span>.</span><span>text</span> <span>=</span> <span>'</span><span>This is some text</span><span>'</span><span>;</span>
<span>r</span><span>.</span><span>context</span><span>.</span><span>greet</span> <span>=</span> <span>(</span><span>name</span><span>)</span> <span>=></span> <span>console</span><span>.</span><span>log</span><span>(</span><span>`hello </span><span>${</span><span>name</span><span>}</span><span>`</span><span>);</span>
// include the repl library const repl = require('repl'); // start it up, with the desired prompt string const r = repl.start('> '); // inject a couple pieces of context r.context.text = 'This is some text'; r.context.greet = (name) => console.log(`hello ${name}`);

Enter fullscreen mode Exit fullscreen mode

We can save this as my_repl.js and then start it up and use it as follows (note that text and greet are already defined for you because they were injected into the context):

user@comp ~<span>$ </span>node my_repl.js
<span>></span>
user@comp ~<span>$ </span>node my_repl.js 
<span>></span>
user@comp ~$ node my_repl.js >

Enter fullscreen mode Exit fullscreen mode

<span>></span> <span>1</span><span>+</span><span>1</span>
<span>2</span>
<span>></span> <span>text</span>
<span>'</span><span>This is some text</span><span>'</span>
<span>></span> <span>greet</span><span>(</span><span>'</span><span>Jon</span><span>'</span><span>)</span>
<span>hello</span> <span>Jon</span>
<span>undefined</span>
<span>></span> <span>const</span> <span>greetAndCompliment</span> <span>=</span> <span>(</span><span>name</span><span>)</span> <span>=></span> <span>{</span>
<span>...</span> <span>greet</span><span>(</span><span>name</span><span>);</span>
<span>...</span> <span>console</span><span>.</span><span>log</span><span>(</span><span>'</span><span>nice code</span><span>'</span><span>);</span>
<span>...</span> <span>}</span>
<span>undefined</span>
<span>></span> <span>greetAndCompliment</span><span>(</span><span>'</span><span>Jon</span><span>'</span><span>)</span>
<span>hello</span> <span>Jon</span>
<span>nice</span> <span>code</span>
<span>undefined</span>
<span>></span>
<span>></span> <span>1</span><span>+</span><span>1</span>
<span>2</span>
<span>></span> <span>text</span>
<span>'</span><span>This is some text</span><span>'</span>
<span>></span> <span>greet</span><span>(</span><span>'</span><span>Jon</span><span>'</span><span>)</span>
<span>hello</span> <span>Jon</span>
<span>undefined</span>
<span>></span> <span>const</span> <span>greetAndCompliment</span> <span>=</span> <span>(</span><span>name</span><span>)</span> <span>=></span> <span>{</span>
<span>...</span>   <span>greet</span><span>(</span><span>name</span><span>);</span>
<span>...</span>   <span>console</span><span>.</span><span>log</span><span>(</span><span>'</span><span>nice code</span><span>'</span><span>);</span>
<span>...</span> <span>}</span>
<span>undefined</span>
<span>></span> <span>greetAndCompliment</span><span>(</span><span>'</span><span>Jon</span><span>'</span><span>)</span>
<span>hello</span> <span>Jon</span>
<span>nice</span> <span>code</span>
<span>undefined</span>
<span>></span> 
> 1+1 2 > text 'This is some text' > greet('Jon') hello Jon undefined > const greetAndCompliment = (name) => { ... greet(name); ... console.log('nice code'); ... } undefined > greetAndCompliment('Jon') hello Jon nice code undefined >

Enter fullscreen mode Exit fullscreen mode

Everyday Uses

I find REPLs most useful when trying out a simple experiment. For example, instead of creating a test.py script to confirm that default parameters work the way I think they do, I can just fire up the REPL and confirm it:

<span>>>></span> <span>def</span> <span>print_greeting</span><span>(</span><span>greeting</span><span>=</span><span>'hello world'</span><span>):</span>
<span>...</span> <span>print</span><span>(</span><span>greeting</span><span>)</span>
<span>...</span>
<span>>>></span> <span>print_greeting</span><span>()</span>
<span>hello</span> <span>world</span>
<span>>>></span> <span>print_greeting</span><span>(</span><span>'hello overridden default'</span><span>)</span>
<span>hello</span> <span>overridden</span> <span>default</span>
<span>>>></span> <span>def</span> <span>print_greeting</span><span>(</span><span>greeting</span><span>=</span><span>'hello world'</span><span>):</span>
<span>...</span>     <span>print</span><span>(</span><span>greeting</span><span>)</span>
<span>...</span> 
<span>>>></span> <span>print_greeting</span><span>()</span>
<span>hello</span> <span>world</span>
<span>>>></span> <span>print_greeting</span><span>(</span><span>'hello overridden default'</span><span>)</span>
<span>hello</span> <span>overridden</span> <span>default</span>
>>> def print_greeting(greeting='hello world'): ... print(greeting) ... >>> print_greeting() hello world >>> print_greeting('hello overridden default') hello overridden default

Enter fullscreen mode Exit fullscreen mode

Wrap Up

Now that you’ve learned about REPLs, you might also be interested in unit tests, and Test-Driven Development, or TDD. These increase developer velocity in a similar way, by shortening cycle time. They have the added advantage of increasing code quality. For further reading and REPLing, check out the Wikipedia page or repl.it.

Thanks for reading!

原文链接:Moving faster with REPL

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
Death comes to all, but great achievements raise a monument which shall endure until the sun grows old.
死亡无人能免,但非凡的成就会树起一座纪念碑,它将一直立到太阳冷却之时
评论 抢沙发

请登录后发表评论

    暂无评论内容