Friday, July 15, 2016

Backticks

Most languages support running arbitrary commands using something like the Linux system function. Often, this support has both quick-and-easy and full-featured-but-complex versions.

In Python, you can use os.system:

>>> os.system("ls -l")

In Ruby, you can use system as well as "backticks":

irb(main):001:0> system("ls -l")

irb(main):002:0> `ls -l`

Basically, the difference between "system" and "backticks" is:

  • "system" executes a command, returning the exit code of the process.
  • "backticks" executes a command, returning the standard output of the process.

Factor has extensive cross-platform support for launching processes, but I thought it would be fun to show how custom syntax can be created to implement "backticks", capturing and returning standard output from the process:

SYNTAX: `
    "`" parse-multiline-string '[
        _ utf8 [ contents ] with-process-reader
    ] append! ;

You can use this in a similar fashion to Ruby or Perl:

IN: scratchpad ` ls -l`
Note: This syntax currently requires a space after the leading backtick. In the future, we have plans for an improved lexer that removes this requirement.

This is available in the backticks vocabulary.

Wednesday, July 6, 2016

Clock Angles

Programming Praxis posted about calculating clock angles, specifically to:

Write a program that, given a time as hours and minutes (using a 12-hour clock), calculates the angle between the two hands. For instance, at 2:00 the angle is 60°.

Wikipedia has a page about clock angle problems that we can pull a few test cases from:

{ 0 } [ "12:00" clock-angle ] unit-test
{ 60 } [ "2:00" clock-angle ] unit-test
{ 180 } [ "6:00" clock-angle ] unit-test
{ 18 } [ "5:24" clock-angle ] unit-test
{ 50 } [ "2:20" clock-angle ] unit-test

The hour hand moves 360° in 12 hours and depends on the number of hours and minutes (properly handling midnight and noon to be ):

:: hour° ( hour minutes -- degrees )
    hour [ 12 = 0 ] keep ? minutes 60 / + 360/12 * ;

The minute hand moves 360° in 60 minutes:

: minute° ( minutes -- degrees )
    360/60 * ;

Using these words, we can calculate the clock angle from a time string:

: clock-angle ( string -- degrees )
    ":" split1 [ number>string ] bi@
    [ hour° ] [ minute° ] bi - abs ;