tag:blogger.com,1999:blog-69257522024-03-08T10:31:48.960+08:00Pun Intended ConsequencesIn which the main character rambles on about stuff.Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.comBlogger136125tag:blogger.com,1999:blog-6925752.post-847841609615043122020-01-26T05:48:00.001+08:002020-01-26T05:48:09.609+08:00Does Betteridge's Law of Headlines ever NOT apply?No.Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-53427977094398868022017-09-11T07:29:00.000+08:002017-09-11T07:30:03.564+08:00BuckleScript Gradual Typing: Incremental Change<p>IN THE <a
href="http://yawar.blogspot.ca/2017/09/gradual-typing-of-javascript-using.html">previous
post</a>, I showed a basic example of overlaying an OCaml type over a
dynamically-typed JavaScript function, using BuckleScript's FFI feature.
In this post, I will show a slightly more complex example: binding to
the Web API's <a
href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat"><code><i>Intl</i>.<i>DateTimeFormat</i></code></a>
constructor. As usual, you can follow along by typing and pasting code
into the <a
href="https://bucklescript.github.io/bucklescript-playground/">BuckleScript
playground</a>.</p>
<p>In JavaScript, we would use the constructor like:</p>
<div class="code"><code>
<b>const</b> <i>format</i> =<br />
<b>new</b> <i>Intl</i>.<i>DateTimeFormat</i>("en-CA", { <i>hour12</i>: <b>false</b> });
</code></div>
<p>We do need to note, though, that both of the arguments to
<code><i>Intl</i>.<i>DateTimeFormat</i></code> are optional, and will be
given default values if they are not passed in. So really in our
BuckleScript binding we want to somehow make them optional as well.</p>
<p>Fortunately, OCaml and BuckleScript allow for optional function
parameters, as long as we make the <em>final</em> parameter
non-optional:</p>
<div class="code"><code>
<b>type</b> <b><i>dateTimeFormat</i></b><br />
<br />
<b>external</b> <i>dateTimeFormat_make</i> :<br />
?<i>locales</i>:<b><i>'locales</i></b> -> ?<i>options</i>:<b><i>'options</i></b> -> <b><i>unit</i></b> -> <b><i>dateTimeFormat</i></b> =<br />
"Intl.DateTimeFormat" [@@bs.new]<br />
<br />
<b>let</b> <i>format</i> =<br />
<i>dateTimeFormat_make</i><br />
~<i>locales</i>:"en-CA" ~<i>options</i>:[%obj { <i>hour12</i> = <b>false</b> }] ()<br />
</code></div>
<p>We introduce several new concepts here:</p>
<p><code><b>type</b> <b><i>dateTimeFormat</i></b></code> is an abstract
type that, for now, is defined only by the fact that we create values of
the type with:</p>
<p><code><b>external</b> <i>dateTimeFormat_make</i> ...</code> is a
binding to a constructor (thanks to the <a
href="https://bucklescript.github.io/bucklescript/Manual.html#_binding_to_javascript_constructor_code_bs_new_code"><code>[@@bs.new]</code></a>
attribute) which takes optional locales and options arguments, a
required unit argument, and returns an instance of
<code><b><i>dateTimeFormat</i></b></code>. The optional parameters are
marked by the '?' symbol.</p>
<p><code><b>let</b> <i>format</i> = ...</code> is a usage of the
<code><i>dateTimeFormat_make</i></code> FFI binding to force
BuckleScript to actually generate a call to the
<code><i>Intl</i>.<i>DateTimeFormat</i></code> constructor. By default
BuckleScript only generates JavaScript output lazily.</p>
<p>In the spirit of gradual typing, I've also been lazy about working
out the actual types of the parameters to the
<code><i>dateTimeFormat_make</i></code> binding. Partly it's because the
free type variables <code><b><i>'locales</i></b></code> and
<code><b><i>'options</i></b></code> allow me to pass in <em>any</em>
type of argument into those slots. In the previous snippet, I passed in
the correct types (a string and a JavaScript object with a valid
keyword) intentionally, but there is no type-level guarantee that I have
to do so. I could have passed in values of invalid types, and
BuckleScript would merrily generate JavaScript which would only fail at
runtime.</p>
<p>So how can I force some more measure of type safety into the bindings
here? Well, for the <code><i>locales</i></code> parameter, the Web API
reference for <code><i>Intl</i>.<i>DateTimeFormat</i></code> says its
type has to be either a string or an array of strings. In BuckleScript,
we can model this 'either-or' scenario using the
<a
href="https://bucklescript.github.io/bucklescript/Manual.html#_using_polymorphic_variant_to_model_arguments_of_multiple_possible_types_since_1_8_3"><code>[@bs.unwrap]</code></a>
attribute:</p>
<div class="code"><code>
<b>external</b> <i>dateTimeFormat_make</i> :<br />
?<i>locales</i>:([ <i>`one</i> <b>of</b> <b><i>string</i></b> | <i>`many</i> <b>of</b> <b><i>string</i></b> <b><i>array</i></b> ] [@bs.unwrap]) -><br />
?<i>options</i>:<b><i>'options</i></b> -><br />
<b><i>unit</i></b> -><br />
<b><i>dateTimeFormat</i></b> =<br />
"Intl.DateTimeFormat" [@@bs.new]<br />
<br />
<b>let</b> <i>formatOne</i> = <i>dateTimeFormat_make</i> ~<i>locales</i>:(<i>`one</i> "en-CA") ()<br />
<br />
<b>let</b> <i>formatMany</i> = <i>dateTimeFormat_make</i> ~<i>locales</i>:(<i>`many</i> [|"en-US"; "en-CA"|]) ()
</code></div>
<p>Now, we can pass locales only as a single string or as an array of
strings. Anything else is a type error. The compiler does need some help
though, to statically tell the difference; hence we have to use
polymorphic variants to differentiate one case from the other.</p>
<p>Note that I left out the <code><i>options</i></code> argument in
these cases to make them simpler. If you paste this into the playground,
you'll see BuckleScript generates <code><b>undefined</b></code>
arguments in their place.</p>
<p>This post is getting rather long now, so I'll explore how to make the
<code><i>options</i></code> argument more type-safe in the next one.
It's going to be quite fun, because there's quite a lot we can do in
BuckleScript to enforce the business rules of the API at the type
level!</p>
Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-86752638409247071512017-09-06T05:18:00.000+08:002017-09-07T09:51:02.896+08:00Gradual Typing of JavaScript Using BuckleScript<p>USUALLY when we say 'gradual typing', we mean gradually adding type
annotations to a dynamically typed codebase like JavaScript or Python,
and then running it through a typechecker like Flow/TypeScript/mypy.
However, an equivalent approach is to leave the existing codebase as it
is, write typed bindings to it using the FFI capabilities of a
statically-typed language, and use those typed bindings to interact with
it.</p>
<p>This of course implies that we have no intention of retiring the
original codebase; we simply want to interoperate with it as safely as
possible. This is an especially ideal scenario when we're dealing with a
massively successful and active body of code like that of the JavaScript
community.</p>
<p>In fact, TypeScript and mypy themselves adopt this approach--using
typed bindings. Their communities maintain massive libraries of library
bindings ready for consumption. In this post, I'm going to demonstrate
how <a
href="http://yawar.blogspot.ca/2017/01/bucklescript-significant-new-ocaml-to.html">BuckleScript</a>
actually allows us to gradually introduce type-safe bindings to existing
JavaScript APIs.</p>
<h2>console.log</h2>
<p>We'll start with a simple example. From using JavaScript before, we
will know that the built-in JavaScript Web API function
<code>console.log</code> prints out an object that we give it on the
browser's JavaScript log:</p>
<div class="code">
<code><i>console</i>.<i>log</i>(<i>obj</i>);</code>
</div>
<p>So in BuckleScript terms, we want to bind to a global value
<code><i>console</i>.<i>log</i></code> that takes a single value and
returns ... nothing. However, in BuckleScript (i.e., OCaml), all
functions have to return <em>some</em> value. What do we return when we
return nothing?</p>
<p>Well, since we're practising gradual typing, we won't worry about
that right now, we'll just say that we return 'whatever':</p>
<div class="code">
<code><b>external</b> <i>consoleLog</i> : <b><i>'obj</i></b> -> <b><i>_</i></b> = "console.log" [@@bs.val]</code>
</div>
<p>According to the BuckleScript manual, the <a
href="https://bucklescript.github.io/bucklescript/Manual.html#_binding_to_global_value_code_bs_val_code"><code>[@@bs.val]</code></a>
attribute binds a given name to a given global value. In this case, the
value is the <code><i>console</i>.<i>log</i></code> function. The
<code><b><i>'obj</i></b></code> type means 'any type, let's call it
"obj" ', and the <code><b><i>_</i></b></code> 'wildcard' type means 'I
don't care what the type is, let the typechecker infer it'.</p>
<p>If you bind and then call this function in the <a
href="https://bucklescript.github.io/bucklescript-playground/">BuckleScript
playground</a>:</p>
<div class="code">
<code><b>external</b> <i>consoleLog</i> : <b><i>'obj</i></b> -> <b><i>_</i></b> = "console.log" [@@bs.val]<br />
<br />
<b>let</b> () = <i>consoleLog</i> "Hello, World!"</code>
</div>
<p>You get the following JavaScript output:</p>
<div class="code">
<pre>
// Generated by BUCKLESCRIPT VERSION 1.9.2, PLEASE EDIT WITH CARE
'use strict';
console.log("a");
/* Not a pure module */
</pre>
</div>
<p>So, a binding with almost no concrete type information (except that
it's a function of one argument) compiles down to JavaScript that just
works! Admittedly, <code><i>console</i>.<i>log</i></code> is a simple
function which accepts pretty much any input. In the next installment
(this one is getting a little long) I'll cover another slightly more
complex function and show how we can gradually type it in
BuckleScript.</p>Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-77336359543400951632017-03-12T03:16:00.000+08:002017-09-06T06:35:23.790+08:00Idiomatic F# Design<p>HERE are the basic points of idiomatic (according to me) F# design.
The idioms I present below are not the ones generally used in the F#
community; they are fairly controversial. But they <em>are</em> similar
to idioms used in the wider ML languages, and I genuinely believe they
offer value in terms of easy-to-read code.</p>
<h2>Prefer modules, records, and functions</h2>
<p>Try to avoid classes, because they are somewhat higher-ceremony than
plain F# records. For example: records can be destructured effortlessly
and updated immutably by replacing the values of named fields with new
values.</p>
<h2>Avoid member methods and properties</h2>
<p>They don't mesh well with the functional style because they can't be
passed around directly. Module member values and functions can.</p>
<h2>Put everything inside modules</h2>
<p>Ideally, dedicate a module to a (primary) type and name the type just
<code>t</code> to avoid repetition; refer to the type (and other module
members) prefixed by the module name for maximum clarity.</p>
<p>In fact, put everything (types, exceptions, and values) inside
modules; they are an excellent organisational tool and clarify your
thinking about what things go together.</p>
<h2>Design top-down using interface (.fsi) files</h2>
<p>F# is fantastic for top-down design because you can write the
signatures of your modules, data, and operations separately as
syntactically valid code in .fsi (F# interface) files and then fill in
the blanks later with the actual implementation (.fs) files. Even if you
don't consider yourself a top-down thinker, give it a try and you may be
surprised by F#'s expressive power here.</p>
<p>Interface files are like C/C++ header files, and let you hide any
module members you don't want to expose. Crucially, they also let you
hide data definitions and give your caller abstract types to work with,
enabling information hiding and decoupling. Quick example:</p>
<div class="code">
<pre>
(* person.fsi *)
namespace MyProject
module Person =
type t
val make : string -> t
val id : t -> int64
val name : t -> string
val with_name : string -> t -> t
(* person.fs *)
namespace MyProject
module Person =
type t = { id : int64; name : string }
let make name = { id = Id_service.get (); name = name }
let id { id = i } = i
let name { name = n } = n
let with_name new_name t = { t with name = new_name }
</pre>
</div>
<p>In the above example, we hide the <code>Person.t</code> type's
implementation details so that callers can't create values of the type
themselves bypassing our API. Nor can they operate on values of the type
in any way except the ones we provide as part of the <code>Person</code>
module.</p>
<p>Also, we take advantage of the above-mentioned F# destructuring
pattern matching and immutable record update--benefits we don't get from
OOP style--to quickly access and change exactly the parts of the data
we're interested in.</p>
<h2>Use classic ML-style type parameter application</h2>
<p>The recommended style of type parameter application in .NET is with
angle brackets after the type constructor. But this is noisy, and just
gets noisier as your types get more complex. Use ML-style, which
reverses the order of application to postfix, but gets rid of (most of)
the noise. Let's compare:</p>
<div class="code">
<pre>
type a1 = Async<option<Person.t>>
type a2 = Person.t option Async
type b1 = Choice<string, Person.t>
type b2 = (string, Person.t) Choice
type c1<'a> = Map<string, 'a>
type 'a c2 = (string, 'a) Map
</pre>
</div>
<p>ML-style type application gives you the biggest wins for sequences of
single-parameter applications, but it still spaces out the code in
general, which helps with reading.</p>
<h2>Use type parameters to control allowed operations</h2>
<p>When your type has operations that are only valid when the type is in
a certain <em>state,</em> then you can express it as a discriminated
union (a sum type) so that operations work in different ways for
different cases of the DU. But the problem with exposing the cases of a
DU is that you lose decoupling--you can't easily control future
refactoring of the type because user code will depend on existing DU
cases.</p>
<p>Another problem is, maybe certain operations don't work for
<em>all</em> states of a type. Let's try an example:</p>
<div class="code">
<pre>
namespace MyProject
module Bulb =
type t = On | Off
exception Already_on
exception Already_off
let turn_on = function
| Off -> On
| On -> raise Already_on
let turn_off = function
| On -> Off
| Off -> raise Already_off
</pre>
</div>
<p>Both of our critical operations on the <code>Bulb.t</code> type are
raising exceptions if called wrongly. Sure, we could have returned a
<code>None : Bulb.t option</code> instead if something went wrong; but
that just passes the checking to the caller somewhere else. There is a
better way: phantom types. Here's the above example converted:</p>
<div class="code">
<pre>
(* bulb.fsi *)
namespace MyProject
module Bulb =
type on
type off
type 'a t
val on : on t
val off : off t
val turn_on : off t -> on t
val turn_off : on t -> off t
(* bulb.fs *)
namespace MyProject
module Bulb =
type on = interface end
type off = interface end
(* Phantom type--left-hand type parameter isn't used on right hand. *)
type 'a t = On | Off
let on = On
let off = Off
(*
Compile warnings are OK here because we're controlling allowed inputs.
*)
let turn_on Off = On
let turn_off On = Off
</pre>
</div>
<p>Note that the compiler warns us here about incomplete pattern matches
on the <code>Bulb.t</code> type, but we ignore them in this case because
we're explicitly controlling allowable function inputs at the type
level. We can turn off this warning with a <code>#nowarn "25"</code>
compiler directive in the <code>bulb.fs</code> file, but in general
turning off warnings is not a good idea.</p>
<h2>Prefer records of functions to interfaces</h2>
<p><a
href="https://medium.com/@dogwith1eye/prefer-records-of-functions-to-interfaces-d6413af4d2c3#.fz6xkd5tu">Here</a>
is a good write-up about this, but let me reiterate: interface methods
can't be easily passed around, unlike record member functions (which can
be closures, remember). An example:</p>
<div class="code">
<pre>
(* api.fs *)
namespace MyProject
module Api =
exception Invalid_id
type 'a t =
{ get_exn : int64 -> 'a Async
add : 'a -> unit Async
remove_exn : int64 -> unit Async
list : unit -> 'a seq Async }
(* person.fs *)
namespace MyProject
module Person =
type t = { id : int64; name : string }
let make id name = { id = id; name = name }
let id { id = i } = i
let name { name = n } = n
(* val api : t Api.t *)
let api =
{ get_exn = fun id -> ...
add = fun person -> ...
remove_exn = fun id -> ...
list = fun () -> ... }
</pre>
</div>
<p>Above we implement a generic data store API and a domain type that
implements the API. Note that as a convention we add an
<code>_exn</code> suffix to code which might raise an exception. This
helps the reader prepare to reason about exception handling.</p>
<h2>Wrap OOP-style APIs in modular F#</h2>
<p>When dealing with traditional OOP-style APIs, e.g. Windows Forms, try
to wrap them up in modular F# and expose only the F# abstraction. E.g.,
suppose you're writing a simple GUI calculator app in WinForms. You need
to (1) write out the logic and make it testable; and (2) render the GUI
in a form. Solution--put these things in a module:</p>
<div class="code">
<pre>
(* calculator.fsi *)
namespace CalculatorApp
module Calculator =
type number = Zero | One | Two | ... | Nine
type op = Plus | Minus | ... | Sqrt
type t
val init : t
(*
We will implement these operations as mutating to allow a more fluent,
pipeline-based API like:
let result =
calc
|> clear
|> press_number Five
|> press_op Plus
|> press_number Six
|> calculate
At this point, `calc` is in the state that it holds a calculation
result. We can `clear` it to do more calculations.
*)
val clear : t -> t
val press_number : number -> t -> t
val press_op : op -> t -> t
val press_decimal : t -> t
val calculate : t -> double
(*
Draws the app and hooks up event handlers to the above operations.
*)
val render : t -> System.Windows.Forms.Control
</pre>
</div>
<p>Now in the implementation, follow the types to implement the business
logic and the GUI. Note how the logic is testable because the main
operations are exposed, but the messy OOP GUI rendering is not--the
caller just gets back a <code>Control</code> to embed in their main
window. This is composable and readable.</p>
<h2>General philosophy</h2>
<p>To conclude, we aim for these design points:</p>
<ul>
<li>Information hiding with interface files</li>
<li>Simpler, less noisy syntax is better</li>
<li>Modular is better--ideally everything is in a module</li>
<li>Logic encoded in the types is better--you get compile-time
guarantees and have to do less runtime error handling.</li>
</ul>
Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-46019434462547213422017-02-27T00:28:00.000+08:002017-09-07T09:51:15.520+08:00Can F# be liberated from the .NET architecture?<p>Recently I've been thinking about the delicate situation that the F#
language designers find themselves in whenever they want to introduce
new features (especially semantics) into the language, or whenever the
C# team want to introduce features that may affect that language or the
common language runtime.</p>
<p>The problem has clearly existed for a while; F# hasn't gotten any
significant new features since its last major release. The latest
example to pop up is probably the uncertainty over <a
href="https://github.com/fsharp/fslang-suggestions/issues/243#issuecomment-282480054">adding
typeclasses,</a> especially now that it looks like C# is thinking about
adding them too.</p>
<p>So how can F# be freed from its ties to C# and the .NET runtime?
Well, one way would be to split the F# compiler into two parts: the
frontend that compiles F# code to its own intermediate language (let's
call it F# Intermediate Language, or FSIL); and the backend that
compiles FSIL to some other target language like MSIL (or JavaScript
like Fable, JVM bytecode, native, ...).</p>
<h2>Compiling F# to FSIL</h2>
<p>This presents the main advantage that the F# language can evolve
independently of C# and the CLR. The compiler frontend need only worry
about doing a great job of implementing F# syntax and semantics in terms
of a single target representation that it controls fully. The language
can rapidly experiment with new syntax and semantics, or in fact with
the traditional ML language family semantics, just by defining a general
FSIL to target.</p>
<p>Some examples of this would be implementing typeclasses, or ML-style
parameterised modules (functors), or Scala-style implicit evidences, or
an easy-to-use call-by-name function parameter declaration syntax for
easier control-flow DSLs, or higher-kinded types, or ... any of a myriad
of things. All you have to do is teach the frontend to understand your
new syntax and compile it to FSIL.</p>
<p>The nice thing about FSIL is that it would preserve nice concepts
like units of measure, typeclasses, ML modules and functors, etc.,
because it was specifically built to understand them. F# modules would
be compiled down to FSIL files on a one-to-one basis and F#-specific
libraries could be distributed as FSIL packages. Users could link
against them to get the nice higher-level functionality that MSIL
doesn't offer.</p>
<h2>Compiling FSIL to MSIL (and others)</h2>
<p>This step would be concerned with the best way to encode FSIL in
terms of the target language or runtime. E.g., currently F# modules are
encoded as static MSIL classes. This is obviously a great fit, and
others may be found for higher-level F# features.</p>
<p>But no doubt some FSIL functionality would be erased--e.g. functors
would be defunctorised and compiled away to nothing. Any concrete
instantiations of functors would survive as normal modules encoded as
static classes as usual. Or, typeclasses would be compiled down to pass
instances in explicitly in the MSIL encoding.</p>
<p>With this organisation, other backends could spring up. Fable could
become a backend from FSIL to ES5/6/.... Someone could write a backend
for FSIL to JVM, or the Erlang runtime (BEAM), or the OCaml runtime.
There are quite a few possibilities opened up by decoupling the two ends
from each other.</p>
<h2>Optimisation</h2>
<p>With FSIL we would have the opportunity to do separate optimisation
passes on the higher-level, typed, F# focused FSIL, and on the
lower-level CLR (or other target) outputs. We would be able to take
advantage of the information that we would have at those points in the
process while not worrying about the previous or following stages.</p>
<h2>F#ixing up</h2>
<p>There are many advantages to a decoupled frontend/backend design for
the F# toolchain. Possibly the biggest one is that it places F#'s future
as a powerful language squarely in the hands of the F# language
designers, and lifts from them the burden of having to worry about
compatibility with the rest of .NET.</p>
Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-70275914342921326812017-01-21T15:29:00.000+08:002017-01-21T15:29:45.421+08:00BuckleScript: a significant new OCaml to JavaScript compiler<p>RECENTLY I've been paying attention to the <a
href="https://bloomberg.github.io/bucklescript/">BuckleScript</a>
compiler from OCaml to JavaScript (ES5, to be exact). I'm seeing some
significant advances that it brings to the state of the art, and thought
I would share.</p>
<p>A little background: I use Scala.js at work, and it is rock-solid.
Once you're set up with a project, you are pretty much good to go.
Bindings to significant JS libraries are high-quality; I use some of the
biggest names in JS frontend dev libraries today, and all in a nice
Scala-style object-functional layer.</p>
<p>That aside, I still periodically look around the ecosystem and try to
evaluate the latest developments. I've been hearing about BuckleScript
for a while, but only recently decided to try it out for a side project
after trying and failing to understand how <tt>this</tt> works in
JavaScript.</p>
<p>So, without further ceremony, let me present my findings.</p>
<p>BuckleScript's compiler is <em>insanely</em> fast, because Bob Zhang
(the project lead) has taken to heart the OCaml obsession with
performance and routinely tries to optimise away millisecond-level
delays. Once you get a taste of that speed (entire project compiled
faster than you can blink), you'll find it difficult to go back to
something slower. It's like getting to use git after you've used svn all
your life.</p>
<p>It compiles to idiomatic, <em>readable</em> ES5, with nice
indentation, (almost) no name mangling, and a one-to-one mapping from
OCaml modules to ES modules (whichever kind you prefer: Require, AMD,
Google).</p>
<p>It targets and integrates with the existing npm ecosystem;
it doesn't try to introduce yet another package manager. It makes
writing bindings (types) for existing JS libraries reasonably easy, and
the documentation (the <a
href="http://bloomberg.github.io/bucklescript/Manual.html">manual</a>
especially) is fantastic at guiding you through that.</p>
<p>OCaml is a bit of an odd duck syntax-wise, even among the functional
programming languages. There are nuances to get used to. But once you
get used to them, it is a pleasure to program in. And if you just can't
get used to them, you can always try out Facebook's <a
href="http://facebook.github.io/reason/">Reason</a>, which is an
alternative, JavaScript-lookalike syntax for OCaml.</p>
<p>This focus on integration and ease of reuse of the JavaScript
ecosystem means it's feasible to leverage the npm package collection in
your pure OCaml project. You can deploy a backend server which performs
core functions as a statically compiled, native binary (i.e. not
nodejs); deploy ES5 nodejs services which take advantage of specialised
npm packages for MSSQL querying, or SOAP clients, or what have you; and
you can deploy ES5 in your frontend webapp scripts, all written in pure
OCaml.</p>
<p>So, why OCaml specifically? After all, there are plenty of nice
languages out there.</p>
<p>As it turns out, that OCaml obsession with speed <em>and</em>
type-safety together serve it well here. It's a pragmatic, simple, and
matter-of-fact language, and its runtime model maps very well to the
JavaScript runtime model, while also preserving important compile-time
safety guarantees.</p>
<p>I should emphasise that it's <em>pragmatic</em>: you're not forced to
deal with the added mental load of monads and other type system rabbit
holes--but they're all available if you need them! Personally, I feel
that laziness, purity, and monads have driven away more people than
they've attracted. I think that OCaml gets the balance right. Others
obviously feel differently. But in concrete terms, BuckleScript is a
significant contribution that shouldn't be missed.</p>
<p>If you've developed in a compiled language for any length of time and
like type-safety guarantees, after trying BuckleScript you'll be asking
yourself how much time you've wasted over the years waiting for your
compiler to finish so you can continue your edit-compile cycle. Maybe
it's best not to think too much about that.</p>
Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-70237154575879908172016-11-04T07:03:00.000+08:002016-11-04T07:03:16.941+08:00NanaNANA is what I called him, but to the world he is the late Lutful Quadir Chowdhury, a well-loved husband, father, grandfather, prominent in the respect he earned from his large extended family, and a highly-regarded elder statesman of the South Asian banking community. For a time he settled down and raised his family in then-West Pakistan, but when the time came he chose to migrate to the newly-formed Bangladesh.<br />
<br />
My Nana was a foundational rock of my childhood in Dhaka. To me his spacious home compound, with its large bungalow, lush green back lawn, and giant driveway with two garages at opposite ends, were my personal domain to explore and play in. I have many happy hours of running, jumping, cycling, cricket, soccer, badminton, carrom-board, Monopoly ... and every other childhood activity there. I remember monsoon seasons when we would bring the storm shutters down and the family would gather for tea and watch the rain pour down outside through the wall-to-wall balcony windows. Hours and hours of poring through his rooms and shelves filled to bursting with books. To this day I have dreams that are set in that house.<br />
<br />
Nana was a collector of knick-knacks that any hipster today would give his right arm for. Hand-powered ice-cream makers, spotless Swiss food processor sets, a video cassette recorder that he would bring out to keep me entertained, a slide rule he gave me when I showed signs of interest in math ... but books got the pride of place in his home. They were proudly displayed on his shelves, kept in storage in room after room, kept near his side of the bed for easy access. I would spend hours entranced by those books. Every subject you can think of, from Greek mythology to Somerset Maugham, O. Henry (<i>The Gift of the Magi</i>) to Khushwant Singh. I, a small child, absorbed as much of them as he would lend me, like a sponge. They awakened my interest in chess, algebra, calculus, mythology, history, essays, poetry, ... the world.<br />
<br />
He would take me for fun-filled trips to the video cassette rental store, treat us out to fast food, order in food whenever we visited (we accidentally got cuttlefish once instead of his order of cutlets), show me how he recorded his expenses in his ledger, and all the while carry out his responsibilities as a busy man even after retirement.<br />
<br />
He would receive many visitors, whether friends, family, or others; to some he would give the help or advice they sought; with others he would enjoy a few rounds of chess; and from others he would procure various services: palm tree tappers, snake charmers, gardeners, hairdressers....<br />
<br />
He would make the rounds of his home every evening, one of his well-loved flashlights in hand, checking that all windows were securely fastened, all doors were locked and bolted shut, and that all of his household were accounted for. He would discourage anyone from leaving the house after nightfall, and be up again in the early morning, making sure everyone was awake. I've never been a morning person, and he always had to spend quite a lot of time convincing me to wake up.<br />
<br />
I think Nana, coming from a <i>zamindari</i> (landowning) family that lost much of its wealth to the turbulent times, had an idea in his mind of what his life should be as a patriarch of his family, and he made that a reality through sheer hard work and persistence. He created an evergreen world, a perfect world for a childhood.<br />
<br />
In the years after that, I was away from Bangladesh most of the time. I didn't get the chance or take the opportunity to see Nana as much as I should have. For years I kept telling myself I would meet him again and we would have another game of chess. Earlier this year I finally saw him and we had our game. I told him I would come back and we would have a rematch, and he agreed. I told him my younger brother would visit him soon, and he was glad to hear it. It gave him something to look forward to. I'm so grateful I was able to keep at least one promise.<br />
<br />
After his passing, my overwhelming feeling is gratitude that I knew him.Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-11348350582089473752016-10-16T14:03:00.000+08:002016-10-16T14:03:27.824+08:00The Birkana hexadecimal number symbols<p>AMONG number systems, the hexadecimal system of counting (or 'radix') has a special place in the hearts of programmers, being closely related to binary, the fundamental number system used by all modern computers. Unlike decimal, which counts ten numbers (0 through 9) before having to add a 'place' (an order of magnitude), hexadecimal allows us to count sixteen numbers (0 through 9, then A through F) before having to add a place.</p>
<p>While the hexadecimal notation of using the first six letters of the alphabet is practical in a rough-and-ready sort of way, no one ever accused it of being elegant. There does, however, exist a fairly elegant (and I think clever) notation for writing hexadecimal--it's called Birkana. The only problem with Birkana is that most of the internet seems to have forgotten about it.</p>
<p>Well, almost all. I obviously came across Birkana somewhere on the internet at some point, years ago. And there may well be many posts written about it in the back reaches of the Google search engine. But to this day, the only result I've managed to find in my searches has been a <a href="https://beta.groups.yahoo.com/neo/groups/sliderule/conversations/messages/38155">mailing list post</a> in the discussions of The International Slide Rule Group--probably not a very prominent corner of the online world.</p>
<p>That's too bad, because Birkana is pretty cool and it does deserve a proper introduction. So, what is it exactly?</p>
<p>Birkana is a <a href="https://en.wikipedia.org/wiki/Runes">Runic</a> symbol set for expressing the hexadecimal number radix, but it's designed in such a way that the exact shape of each number rune is built by combining a basic shape for the number zero and <em>accents</em> which correspond to the numbers 1, 2, 4, and 8. In the right combinations, they can express any number from 0 to F. Here are the shapes for the 'building block' numbers:</p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="32">
<line x1="0" y1="0" x2="0" y2="32" stroke="black" stroke-width="2"/>
<svg>
<span style="margin-left: 6px">0x0</span>
</p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="32">
<line x1="0" y1="0" x2="0" y2="32" stroke="black" stroke-width="2"/>
<line x1="0" y1="0" x2="8" y2="8" stroke="black" stroke-width="2"/>
<svg>
<span style="margin-left: 6px">0x1</span>
</p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="32">
<line x1="0" y1="0" x2="0" y2="32" stroke="black" stroke-width="2"/>
<line x1="0" y1="16" x2="8" y2="8" stroke="black" stroke-width="2"/>
<svg>
<span style="margin-left: 6px">0x2</span>
</p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="32">
<line x1="0" y1="0" x2="0" y2="32" stroke="black" stroke-width="2"/>
<line x1="0" y1="16" x2="8" y2="24" stroke="black" stroke-width="2"/>
<svg>
<span style="margin-left: 6px">0x4</span>
</p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="32">
<line x1="0" y1="0" x2="0" y2="32" stroke="black" stroke-width="2"/>
<line x1="0" y1="32" x2="8" y2="24" stroke="black" stroke-width="2"/>
<svg>
<span style="margin-left: 6px">0x8</span>
</p>
<p>As you can see, every combination of the zero line and the accents will give us a hexadecimal number (between 0 and F). I find it easiest to sum up starting at the highest possible number, then adding on the next-highest number, and so on. Some examples:</p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="32">
<line x1="0" y1="0" x2="0" y2="32" stroke="black" stroke-width="2"/> <!-- 0 -->
<line x1="0" y1="0" x2="8" y2="8" stroke="black" stroke-width="2"/> <!-- 1 -->
<line x1="0" y1="16" x2="8" y2="8" stroke="black" stroke-width="2"/> <!-- 2 -->
<svg>
<span style="margin-left: 6px">0x3 (= 0x2 + 0x1)</span>
</p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="32">
<line x1="0" y1="0" x2="0" y2="32" stroke="black" stroke-width="2"/> <!-- 0 -->
<line x1="0" y1="16" x2="8" y2="8" stroke="black" stroke-width="2"/> <!-- 2 -->
<line x1="0" y1="16" x2="8" y2="24" stroke="black" stroke-width="2"/> <!-- 4 -->
<svg>
<span style="margin-left: 6px">0x6 (= 0x4 + 0x2)</span>
</p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="32">
<line x1="0" y1="0" x2="0" y2="32" stroke="black" stroke-width="2"/> <!-- 0 -->
<line x1="0" y1="0" x2="8" y2="8" stroke="black" stroke-width="2"/> <!-- 1 -->
<line x1="0" y1="32" x2="8" y2="24" stroke="black" stroke-width="2"/> <!-- 8 -->
<svg>
<span style="margin-left: 6px">0x9 (= 0x8 + 0x1)</span>
</p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="32">
<line x1="0" y1="0" x2="0" y2="32" stroke="black" stroke-width="2"/> <!-- 0 -->
<line x1="0" y1="0" x2="8" y2="8" stroke="black" stroke-width="2"/> <!-- 1 -->
<line x1="0" y1="16" x2="8" y2="24" stroke="black" stroke-width="2"/> <!-- 4 -->
<line x1="0" y1="32" x2="8" y2="24" stroke="black" stroke-width="2"/> <!-- 8 -->
<svg>
<span style="margin-left: 6px">0xD (= 0x8 + 0x4 + 0x1)</span>
</p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="32">
<line x1="0" y1="0" x2="0" y2="32" stroke="black" stroke-width="2"/> <!-- 0 -->
<line x1="0" y1="0" x2="8" y2="8" stroke="black" stroke-width="2"/> <!-- 1 -->
<line x1="0" y1="16" x2="8" y2="8" stroke="black" stroke-width="2"/> <!-- 2 -->
<line x1="0" y1="16" x2="8" y2="24" stroke="black" stroke-width="2"/> <!-- 4 -->
<line x1="0" y1="32" x2="8" y2="24" stroke="black" stroke-width="2"/> <!-- 8 -->
<svg>
<span style="margin-left: 6px">0xF (= 0x8 + 0x4 + 0x2 + 0x1)</span>
</p>
<p>Notice also the exact positions of the accents--they intersect with the zero line at either the top, middle, or bottom, and they end up parallel to exactly a quarter of the way up or down the zero line. The design may have been inspired by ancient runes, but it is very carefully thought-out.</p>
<p>Unfortunately, at the moment it's not practical to type in Birkana in any digital format. Theoretically, the Unicode Consortium could decide to add the Birkana symbols to the Unicode specification and some enterprising font designer could come up with a set for general use. Until then, you're unlikely to come across Birkana symbols on the internet. So for now, enjoy them here, and feel free to copy the SVG shapes off this page's source.</p>
Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-29958219644697903552016-02-08T02:41:00.000+08:002017-09-06T06:36:14.005+08:00The Essence of Phantom Types in Scala<p>The phantom of the type opera</p>
<p>HEIKO Seeberger over at the Codecentric blog published an interesting
<a
href="https://blog.codecentric.de/en/2016/02/phantom-types-scala">post</a>
about using Scala's typelevel programming to encode phantom types in a
strict way so that you could tightly control the types that are allowed
to be phantasmal.</p>
<p>For example, if you have a <code><i>hacker</i>:
<b><i>Hacker</i></b>[<b><i>Decaffeinated</i></b>]</code>, and you call
<code><i>hacker.hackOn</i></code>, you want a compile-time error saying
essentially that a decaffeinated hacker can't code on.</p>
<p>Heiko's techniques make some tradeoffs:</p>
<ul>
<li>Having to encode the methods' phantom type requirements as type
bound sandwiches or implicit evidence of types. This is required if we
want to keep using object-oriented method call syntax.</li>
<li>Having to bound the <code>Hacker</code>'s phantom type parameter
to an explicit hierarchy of allowed phantom types, i.e. either
<code><b><i>State</i></b></code> or its subtypes
<code><b><i>Caffeinated</i></b></code>,
<code><b><i>Decaffeinated</i></b></code>. I believe this is
unnecessary, as the <code><b><i>Hacker</i></b></code> constructor is
private and the companion object provides smart constructors that
allow you to get only a
<code><b><i>Hacker</i></b>[<i>State</i>.<b><i>Caffeinated</i></b>]</code>
or a
<code><b><i>Hacker</i></b>[<i>State</i>.<b><i>Decaffeinated</i></b>]</code>.</li>
</ul>
<p>If we trade away the object-oriented syntax, and give up the
unnecessary phantom type hierarchy, we get:</p>
<div class="code">
<code><b>class</b> <b><i>Hacker</i></b>[<b><i>S</i></b>] <b>private</b> () /* 1 */<br />
<br />
<b>object</b> <i>Hacker</i> {<br />
<b>trait</b> <b><i>Decaffeinated</i></b> /* 4 */<br />
<b>trait</b> <b><i>Caffeinated</i></b> /* 5 */<br />
<br />
<b>val</b> <i>caffeinated</i>: <b><i>Hacker</i></b>[<b><i>Caffeinated</i></b>] = <b>new</b> <b><i>Hacker</i></b> /* 7 */<br />
<b>val</b> <i>decaffeinated</i>: <b><i>Hacker</i></b>[<b><i>Decaffeinated</i></b>] =<br />
<b>new</b> <b><i>Hacker</i></b> /* 8 */<br />
<br />
<b>def</b> <i>hackOn</i>( /* 10 */<br />
<i>hacker</i>: <b><i>Hacker</i></b>[<b><i>Caffeinated</i></b>]): <b><i>Hacker</i></b>[<b><i>Decaffeinated</i></b>] = {<br />
<i>println</i>("Hacking, hacking, hacking!")<br />
<i>decaffeinated</i> /* 12 */<br />
}<br />
<br />
<b>def</b> <i>drinkCoffee</i>( /* 15 */<br />
<i>hacker</i>: <b><i>Hacker</i></b>[<b><i>Decaffeinated</i></b>]): <b><i>Hacker</i></b>[<b><i>Caffeinated</i></b>] = {<br />
<i>println</i>("Slurp...")<br />
<i>caffeinated</i> /* 18 */<br />
}<br />
}</code>
</div>
<p>In this version, a few things are going on. By line number:</p>
<dl>
<dt>1</dt><dd>We make the phantom type parameter unbound and
invariant, because we made the constructor private. Client code can't
create any <code><b><i>Hacker</i></b></code>s, it can only use the
ones we provide. Also, we move all the logic out of the class body and
into the companion object.</dd>
<dt>4, 5</dt><dd>We don't need a phantom type hierarchy, or even to
seal the traits, because again client code can only use the
<code><b><i>Hacker</i></b></code>s that we provide, and the phantom
type parameter is, as mentioned, invariant. Also, I don't put the
states inside their own companion object because they're merely
incidental to the main logic; they don't have any logic dedicated to
them.</dd>
<dt>7, 8</dt><dd>We provide the smart constructors here. Note that the
constructors don't need to be methods; they can just be values because
these values are immutable. So operations on them can just keep
reusing the same values.</dd>
<dt>10, 15</dt><dd>We make the <code><i>hackOn</i></code> and
<code><i>drinkCoffee</i></code> methods both take and return a
<code><b><i>Hacker</i></b></code> with the correct phantom type to
explicitly show the transitions
<code><b><i>Hacker</i></b>[<b><i>Caffeinated</i></b>] =>
<b><i>Hacker</i></b>[<b><i>Decaffeinated</i></b>]</code> and
<code><b><i>Hacker</i></b>[Decaffeinated] =>
<b><i>Hacker</i></b>[<b><i>Caffeinated</i></b>]</code>.</dd>
<dt>12, 18</dt><dd>We use our own smart constructors internally to
separate interface from implementation as much as possible.</dd>
</dl>
<p>With the above code, we can get the highly desirable 'type mismatch'
error that immediately tells us what's wrong:</p>
<div class="code">
<pre>
scala> Hacker drinkCoffee Hacker.caffeinated
<console>:8: error: type mismatch;
found : Hacker[Hacker.Caffeinated]
required: Hacker[Hacker.Decaffeinated]
Hacker drinkCoffee Hacker.caffeinated
^
scala> Hacker hackOn (Hacker hackOn (Hacker drinkCoffee Hacker.decaffeinated))
<console>:8: error: type mismatch;
found : Hacker[Hacker.Decaffeinated]
required: Hacker[Hacker.Caffeinated]
Hacker hackOn (Hacker hackOn (Hacker drinkCoffee Hacker.decaffeinated))
^
</pre>
</div>
<p>Admittedly, we've given up object-oriented syntax to get here. But I
personally think the tradeoff is worth it.</p>
Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-25910463105736900622015-12-30T13:42:00.000+08:002017-01-23T04:49:07.914+08:00How does the State monad work?<p>HANDLING state in a monadic way is one of the techniques Haskellers
come to learn about. But how does it work, roughly?</p>
<p>The following is a simplified, intuitional explanation of the state
monad. It's basically a trick of function currying. Suppose you have
some program state, and some functions that do something to your program
state:</p>
<p><code><b>type</b> <b><i>MyState</i></b> = <b><i>Int</i></b></code></p>
<p><code><i>increaseState</i> :: <b><i>MyState</i></b> -> <b><i>Int</i></b> -> <b><i>MyState</i></b><br />
<i>increaseState myState n</i> = <i>myState</i> + <i>n</i></code></p>
<p><code><i>decreaseState</i> :: <b><i>MyState</i></b> -> <b><i>Int</i></b> -> <b><i>MyState</i></b><br />
<i>decreaseState myState n</i> = <i>myState</i> - <i>n</i></code></p>
<p>That's workable, but it's not composable: it's inconvenient to keep
wrapping function calls like:</p>
<p><code><b>let</b> <i>myState</i> = 0<br />
<b>in</b> <i>increaseState</i> (<i>decreaseState myState</i> 1) 2</code></p>
<p>Because the earlier states are wrapped inside the first argument, and
you have to also provide a second argument, you don't get any syntactic
wins here.</p>
<p>But if you express the functions a little differently:</p>
<p><code><i>increaseState</i> :: <b><i>Int</i></b> -> <b><i>MyState</i></b> -> <b><i>MyState</i></b><br />
<i>increaseState n myState</i> = <i>myState</i> + <i>n</i></code></p>
<p><code><i>decreaseState</i> :: <b><i>Int</i></b> -> <b><i>MyState</i></b> -> <b><i>MyState</i></b><br />
<i>decreaseState n myState</i> = <i>myState</i> - <i>n</i></code></p>
<p>You can take advantage of the associativity of the function arrow and
think of the function types as <code><b><i>Int</i></b> ->
(<b><i>MyState</i></b> -> <b><i>MyState</i></b>)</code>. Now, this
return type is a transformation from an initial state to a final state.
If we alias the type: <code><b>type</b> <b><i>StateWrapper</i></b> =
<b><i>MyState</i></b> -> <b><i>MyState</i></b></code>, we can write our
function types as <code><b><i>Int</i></b> ->
<b><i>StateWrapper</i></b></code>.</p>
<p>So, the new function types are:</p>
<p><code><i>increaseState</i>, <i>decreaseState</i> :: <b><i>Int</i></b> -> <b><i>StateWrapper</i></b></code></p>
<p>If we say <code><i>increaseState</i> 2</code>, we get a result of
type <code><b><i>StateWrapper</i></b></code>. If we say
<code><i>decreaseState</i> 1</code>, we get a result also of type
<code><b><i>StateWrapper</i></b></code>. If we compose these two values
(which are actually functions, remember), we get a final value of type
<code><b><i>StateWrapper</i></b></code>, that is
<code><b><i>MyState</i></b> -> <b><i>MyState</i></b></code>. In fact, no
matter how many stateful operations we do, if we compose them all in
sequence, we get a final function of <code><b><i>MyState</i></b> ->
<b><i>MyState</i></b></code>.</p>
<p>At the end of the sequencing (the composition), all we have to do is
feed in the initial state, and we get back the final state after
carrying out all the 'stateful' operations.</p>
<p>So, you ask, why the need for a state monad at all? Why not just do
function composition in the first place? The answer is that the state
wrapper type is slightly more complicated than what we've seen above. In
reality, it's closer to <code><b>type</b> <b><i>StateWrapper s a</i></b>
= <b><i>s</i></b> -> (<b><i>a</i></b>, <b><i>s</i></b>)</code>, that is,
given an initial state <code><i>s</i></code>, it returns a result value
<code><i>a</i></code> and a final state <code><i>s</i></code>. A series
of functions of this type can't be composed together using normal
function composition; and hence we use monadic binding to do the
job.</p>
<p>So monadic binding is a more powerful form of function composition
and hence action sequencing that can handle unruly types (but which
still follow a certain pattern, hence the famous <code>(>>=) :: <b><i>m
a</i></b> -> (<b><i>a</i></b> -> <b><i>m b</i></b>) -> <b><i>m
b</i></b>)</code>.</p>
<p>To get a more accurate idea of how the state monad works, see Graham
Hutton's excellent <a
href="http://www.cs.nott.ac.uk/~pszgmh/monads">tutorial</a>.</p>
Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-85047310743655027802015-02-03T11:30:00.000+08:002015-02-03T12:01:13.923+08:00Show the Structure of Your GUI in Your Code<p>I LIKE creating my GUIs programmatically. I suppose I'm a
traditionalist (some would say a masochist). But I feel that it gives me
more control over the design and keeps together things that should live
together.</p>
<p>The downside to this is, lots of objects all declared in the same
scope, with no structure to give you a hint as to how they all fit
together:</p>
<pre>
class View {
Form frm = new Form();
FlowLayoutPanel pnl = new FlowLayoutPanel();
TabControl tbc = new TabControl();
TabPage tbp1 = new TabPage();
Label lbl = new Label();
TextBox txt = new TextBox();
TabPage tbp2 = new TabPage();
Button btn = new Button();
...
}
</pre>
If you think about it though, the controls will all have fixed
parent-child relationships with each other. They will effectively form a
tree structure during runtime, that will give rise to the final
graphical display. In fact, that's what all the XAMLs and JavaFXs and
QMLs of the world model. Why not actually show these relationships <i>in
the code itself</i> with a little bit of indentation trickery?</p>
<pre>
class View {
Form frm = new Form();
FlowLayoutPanel pnl = new FlowLayoutPanel();
TabControl tbc = new TabControl();
TabPage tbp1 = new TabPage();
Label lbl = new Label();
TextBox txt = new TextBox();
TabPage tbp2 = new TabPage();
Button btn = new Button();
...
}
</pre>
<p>A-ha! So the <code>Button</code> won't be inside the
<code>TabPage</code>; it'll be a sibling of the <code>TabControl</code>
itself!</p>
<p>Of course, this is all manual, and won't work with
whitespace-sensitive languages, and can get out of date when you change
your layout, and all those things. But--when it does work, it's
surprising how well it works at organising my thoughts about the layout
into a nice 'graphical' overview.</p>Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-22911445919882677422015-01-08T08:30:00.005+08:002017-09-07T09:51:32.809+08:00Expressive Functional Programming with Continuations in Python<p>In Python, statements and expressions are separate and unequal citizens. For example, statements can contain expressions but expressions can't contain statements. This prevents things like full-powered anonymous functions which can do everything that named functions can, or expression calculations which contain statements like 'import' etc.</p>
<p>I wanted to fix this, to give Python an expressiveness which I thought it was missing. I first thought that we could introduce a new syntax token which could 'wrap' up any number of statements and return the value of the final expression in the block. This turned out to not be feasible, for a couple of reasons, as discussed in the <a href="https://groups.google.com/d/topic/python-ideas/SyY6AiSvSh4/discussion">mailing list</a>.</p>
<p>Then I had the idea that we can turn all statements into expressions. In Python, function calls are expressions. So statements can be wrapped up inside functions to turn them into expressions. Since there aren't that many statements in Python, it's feasible to just do this for all of them. Each of these functions can take a continuation to represent 'the rest of the computation'. If all statements become expressions, and so everything is an expression, this lets us define full anonymous functions because now everything inside the anonymous function can be a single expression!</p>
<h2>Implementation</h2>
<p>To manage the continuations, we first define a data structure: a pair of <code>(continuation, expression)</code> which is passed around among the functions we'll define later, named <code>whatever_</code>. <code>expression</code> in the pair is meant to represent the input to the continuation, if it takes one.</p>
<p>A 'dead' continuation doesn't take an input value.</p>
<p>
<pre>
def __dead(k): return (k, None)
</pre>
</p>
<p>A 'live' continuation takes an input value.</p>
<p>
<pre>
def __live(k, x): return (k, x)
</pre>
</p>
<p>Continuations are run using trampolining to prevent stack overflow, allowing us to overcome the restriction of Python not optimising tail calls. The trampoline takes care of running each continuation with input or not depending on whether it's live or dead.</p>
<p>
<pre>
def run_k_(prog):
(k, x) = prog
while k is not None:
if x is None: (k, x) = k()
else: (k, x) = k(x)
</pre>
</p>
<p>In short, a trampoline function like the above converts recursion into iteration. If you want to learn more about trampolines, <a href="http://blog.moertel.com/posts/2013-06-12-recursion-to-iteration-4-trampolines.html">here's</a> a beautifully simple description of the idea and some examples in Python.</p>
<h2>Some 'Syntax' Definitions</h2>
<p>Below I define some 'syntax' in the form of functions which use continuation-passing style (CPS). So as discussed above, these functions are wrappers for the real syntax, and turn statements into expressions. Note that some of them are fairly simple versions of the real functionality.</p>
<p>A print function which just prints something and then doesn't return a value, it just sets up the rest of the computation to go ahead when it returns. This pattern can be used for all the Python statements.</p>
<p>
<pre>
def print_(x, k):
print x
return __dead(k)
</pre>
</p>
<p>A primitive version of a 'let' binding. This 'returns' a value, i.e. the expr, bound to the parameter name in the continuation lambda. This pattern can be used for all expression-oriented syntax.</p>
<p>
<pre>
def let_(expr, k): return __live(k, expr)
</pre>
</p>
<p>An assertion 'statement'.</p>
<p>
<pre>
def assert_(expr, k):
assert expr
return __dead(k)
</pre>
</p>
<p>An <code>if_</code> 'expression' can 'return' one of two values--so in other words it can pass on either of its input expressions to its continuation.</p>
<p>
<pre>
def if_(test_expr, then_expr, else_expr, k):
if test_expr: return __live(k, then_expr())
else: return __live(k, else_expr())
</pre>
</p>
<p>A <code>cond_</code> is basically a switch statement, but in the form of an expression that again 'returns' a value. Can be used as a replacement for Python's <code>if ... elif ... else ...</code> syntax.</p>
<p>
<pre>
def cond_(test_pairs, default_expr, k):
for (test_expr, then_expr) in test_pairs:
if test_expr: return __live(k, then_expr())
else: return __live(k, default_expr())
</pre>
</p>
<p>We can import a module and pass it along to a continuation, which will then use it and pass it along implicitly to its children continuations through the magic of closures. This is almost like a 'let' binding but it binds the name to the imported module instead of to an expression.</p>
<p>
<pre>
def import_(mod_name, k):
m = __import__(mod_name)
return __live(k, m)
</pre>
</p>
<p>The <code>try_</code> function is different from the others because it actually <i>runs</i> the 'try' continuation and (if needed) the 'except' continuation. This is because it can't just set up two different continuations to be run. It has to run one first to actually find out if there's an exception or not. It returns the 'finally' continuation because the 'finally' block should always be run whether or not an exception occurred, so it's a natural fit for being a continuation.</p>
<p>
<pre>
def try_(expr_k, except_k, finally_k):
try: run_k_(__dead(expr_k))
except: run_k_(__dead(except_k))
finally: return __dead(finally_k)
</pre>
</p>
<p>The <code>for_</code> function also needs to run its <code>act</code> continuation on all the items in its <code>seq</code> (sequence), because there may be a lot of items and just queuing them up for running might build up a <i>huge</i> data structure. It's more efficient to flatten the structure at this point and then just set up the ending continuation after all that.</p>
<p>
<pre>
def for_(seq, act, k):
for x in seq: run_k_(__live(act, x))
return __dead(k)
</pre>
</p>
<h2>Usage</h2>
<p>The end result is that we build and run a large expression that looks kind of like normal code on the left, but ends with a bunch of lambdas on the right of each line. Because Python doesn't have macros or autoclosures, we can't hide the fact that we're passing around lots of functions.</p>
<p>Note that we stop the 'program' at any point by passing in <code>None</code> as the next continuation. You can see this in the functions stored inside the dict below. Also note how we're storing code that looks pretty imperative inside the functions. If you squint a little bit you can kind of ignore the extra clutter and think of each line as a separate 'imperative' statement. Indentation becomes arguably <i>more</i> important here than in normal Python for readability.</p>
<p>Finally, remember that <code>run_k_</code> ('run continuation') runs the whole thing. As long as we compose our program using only functions specially designed to work with the trampolining mechanism, like the ones above, it should all run fine.</p>
<p>
<pre>
if __name__ == "__main__":
run_k_(
let_(
{ "foo":
λ:
print_("I pity the foo!", λ:
for_(range(5), λ x:
print_(x, None), None)),
"bar":
λ:
import_("math", λ m:
let_(5, λ r:
print_("The area of the circle is:", λ:
print_(m.pi * r * r, None)))),
"baz":
λ:
print_("None of your bazness!", None) },
λ dispatch_dict:
# Call to the function inside the dispatch dict is also handled by
# the trampolining mechanism.
dispatch_dict["bar"]()))
</pre>
</p>
<p>For the sake of readability, I've replaced all occurrences of the keyword 'lambda' above with the Greek symbol 'λ'. Of course in real Python code we'll use the keyword (search and replace should do it).</p>
<p>Obviously, you won't want to program like this in normal Python. It would drive people up the wall with crazy. But for specialised use cases like storing a lot of functions inside other data structures, callback-based event handling when you want to do something more complex than just call a function, or building DSLs in Python (hey, <a href="http://www.jclark.com/dsssl/">worse things</a> have happened), this expressive method could come in very handy.</p>
<p>Update: this article describes a simpler, more primitive version of what I currently have. You can follow the latest developments at <a href="https://github.com/yawaramin/lambdak">the GitHub repository</a>.</p>
Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-89186273871976705812014-12-21T13:11:00.001+08:002014-12-21T13:11:33.963+08:00Exodus: Gods and Kings<p>THIS movie should really be called <em>Exodus: Moses’ Struggle with God</em>.</p> <p>Early on in the movie, Moses (at the time an Egyptian general), travels to the city of Pithom to investigate complaints about the Hebrew slaves from the Viceroy assigned to the city. They have a conversation in which the Viceroy mocks the Israelites, saying the very name itself means ‘one who fights with God’. Moses corrects him and says it means ‘one who <em>wrestles</em> with God’. Personally I would use the word ‘struggles’ instead of ‘wrestles’, but the point is that that exchange foreshadows Moses’ relationship with God.</p> <p>As much as the movie is about the suffering and deliverance of the Hebrew people in Egypt, and about how Moses finally finds some measure of happiness in exile with his wife and son, it is more about Moses’ relationship with God–a very personal relationship, almost an equal partnership at times.</p> <p>Moses is very clearly an unbeliever–he has grown up surrounded by the Egyptian religion with its pantheon of gods (not to mention Pharaohs), and has remained unconverted by any of them. He finally decides to follow God (their relationship, as I mentioned, doesn’t even look like any kind of deity worship we have today) because that’s the only way he sees to save his people.</p> <p>Moses sets out to save his people from Pharaoh, but his attempts don’t have much impact, while Rameses’ retaliation seems expressly designed to dispirit and demoralise, frighten and terrorise, the Hebrew slaves. Like any clever slaveowner, Rameses avoids doing much real damage to his property, while still punishing them enough to (in his eyes) frighten them into submission.</p> <p>That it doesn’t work is evident whenever we see the faces of the Hebrews as they observe the injustice. That they persevere in the face of it all seems like the real miracle to me, not the plagues and the cataclysms. Early on in the movie, Moses tells the Viceroy that you can tell a lot about a man by looking into his eyes. When you look at the faces of the Hebrews, it seems as if God is behind their eyes looking out at you.</p> <p>God in the movie is a wrathful God. A God of vengeance. There are no two ways about it. He cannot coerce men nor preempt their minds, having given them free will. But He can and does preempt the natural order and the natures of the beasts and insects, and causes them to rain down upon Egypt in plague after plague. The punishment is intense, the suffering severe. Moses grows frustrated with it. ‘Who are we punishing?’ he asks. When God acts upon the face of the Earth, his action is like a giant hammer that smashes down upon all, without discrimination.</p> <p>The final plague is what finally threatens to break Moses’ resolve: ‘No! I cannot be a part of this!’ In a final act of wrath, God reveals that He has heard Rameses’ threat to kill every Hebrew infant, and He will take the life of every first-born child of Egypt, unless they are in a house whose door is marked with the sacrificial blood of a lamb. Of this escape only the Hebrews are warned. Finally, God plans a way to discriminate between His people and their oppressors.</p> <p>Knowing that there will be a massacre of innocent children is a hard thing to take. Yet the God of the Old Testament has many times been wrathful. He has taken perhaps millions of lives as punishment for evil. The Passover is the first time that He has actually planned out such a massacre with a human general and has chosen who will live and who will die in such a targeted way (well, perhaps since Noah, but then the Ark was also a much cruder means of selecting survivors than what they did for the Passover).</p> <p>The way that God reveals Himself to Moses is interesting. Before I watched the movie, I heard somewhere that God took the form of a British public schoolboy. This intrigued me because it meant that Ridley Scott subscribed to the idea that God, being eternal, experienced all moments of time (past, present, and future) simultaneously and could thus introduce anachronisms by appearing in one time period as something from a completely different time period.</p> <p>But ... I probably took that too literally. It didn’t actually happen. Instead I saw something just as interesting, but in another way. God asks Moses who he is, and Moses replies ‘A shepherd’. God says, ‘I thought you were a general? I need someone who can fight.’ As if He is a wartime leader recruiting a general to lead an army on a front. Which of course He is, and which of course is what He needs Moses to do. The portrayal is very, very interesting when you think about how Yahweh, the Hebrew God, started out in the oldest stories as a legendary warrior hero and leader of his people. In some stories, He had once been in the same position that He now wanted to recruit Moses to.</p> <p>Many times throughout the film, Moses struggles with God, perhaps even chastises Him as being too cruel and vengeful. After four hundred years of watching His people suffer, apparently God has some pent-up wrath. Ultimately though they agree on one thing: the people of Israel need protection and guidance to find their way home.</p> Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-72409244427102210732014-07-07T08:23:00.001+08:002014-07-07T08:23:53.263+08:00Easily Authenticate when Pushing to a Git Remote<p>SOMETIMES when you’re working with git repositories, the remote doesn’t support pushing and pulling over SSH. It only supports HTTPS. Or you don’t have an SSH key properly set up, or you do but it’s not working for some reason. Whatever the cause, the upshot is that whenever you push, you’re forced to type in your username and password. This sucks, understandably. But do you use a password manager, like KeePass, on Windows by any chance? Because if you do, you can authenticate absolutely painlessly. Here’s how.</p> <p>Set up a KeePass entry for the git server you’re pushing to. Let’s use GitHub as an example. Create a GitHub entry with your username and password, then make sure the entry has these two properties:</p> <p>Auto-Type: {USERNAME}{ENTER}{PASSWORD}{ENTER}</p> <p>Auto-Type-Window: Git Bash</p> <p>If you’re using git on Windows, most likely you’re using Git Bash. Of course, if you’re using Posh Git, then just change the window name to whatever is appropriate.</p> <p>Now, when you do a ‘git push’ and the git remote asks you to authenticate, simply press your global autotype combo (by default it’s Ctrl-Alt-K) and KeePass will log you in immediately. No SSH necessary.</p> <p>That’s convenience.</p> Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-56898005175994407622014-05-13T07:45:00.001+08:002014-05-13T07:47:45.857+08:00Stack Overflow and its Discontents<p>LIKE many others, I’ve come to rely on Stack Overflow (SO) as an amazing repository of technical knowledge. How did it become so comprehensive? My guess is it was the ‘many eyes make bugs shallow’ principle. I.e., many contributors building something together, a lot like Wikipedia. SO is nearly always great when you’re searching for an answer, but not that great when you’re trying to contribute and build a profile for yourself among the other members. I’ll explain why but first let me clarify something as I see it: SO may look like a simple Q&A site, but it’s really a permanent knowledge base with the knowledge organised in the form of questions and answers. That’s important: the Q&A format is just that, a knowledge delivery mechanism. So with that in mind, we can examine how that affects peoples’ actions on the site.</p> <p>Lots of people have discussed why SO punishes or rewards contributors the way it does, but one widely-held belief is that there is a subset of users (usually the moderators and other high-reputation users) that is intent on seeing SO’s core mission carried out: that the site becomes a repository of <i>useful</i> and <i>generally applicable</i> questions and answers. To keep it that way, this subset performs <i>triage</i> on the <i>questions</i> that are asked: they apply judgment calls on whether or not the questions are <i>good</i> ones. When you’re a beginner, there are no bad questions. But when you’re building a long-lasting repository, there are bad questions.</p> <p>Generally speaking, bad questions on SO could be any of:</p> <ul> <li>Duplicate of an already-answered question</li> <li>Not phrased as a question</li> <li>Not clear what the asker wants to find out</li> <li>Asker shows no signs of having done any research or made any attempt to solve the problem</li> <li>Question is about a specific corner case which can be easily solved if asker understood a more general principle</li> <li>Code examples are incomplete and can’t be compiled, error messages are not quoted verbatim but only vaguely described</li> <li>And the other end of the spectrum: many screenfuls of code or log output pasted verbatim, in entirety, without any attempt to zoom in on the source of the issue.</li> </ul> <p>Any of these questions will annoy the mods because they’ll invariably get answered (because people are incentivised to answer no matter how bad the question), and then those bad questions and their answers will raise the noise level and make it difficult for people trying to find answers to the genuinely good questions. (Good search features, and even Google, can only take you so far.)</p> <p>So with this in mind, we can start to understand the mods’ behaviour of seemingly penalising usually newer users of the site, those who haven’t absorbed the culture yet and are treating SO as a source of answers to one-off questions. It’s not–the questions are meant to become part of a knowledge base on the subject and potentially live forever. Under these conditions, it’s very difficult to justify questions with the above bad qualities, especially if we can guide the new users towards improving their question quality (and lots of people are trying to do this).</p> <p>So, remember, the mods’ goal is to build a generally-useful knowledge base. With this as a given, the questions (subjects of knowledge) that are of a low quality will tend to get weeded out: either by being downvoted, or closed. The people who’re doing the downvoting and closing don’t have the end goal of <i>punishing</i> the askers; their goal is to <i>weed out</i> the bad questions. That the askers lose rep points is a side effect of the voting and rep system. Which is fair: if my peers judge me as not contributing good material, then I should have less cred. But the primary goal on everyone’s mind is having good material on the site, not punishing me.</p> <p>Having said all that, I want to address the fact that votes on each question and answer are essentially on an infinite scale going in both directions. So, a given question or answer can potentially be upvoted or downvoted many times over, and every one of those votes affects the poster’s rep. But the effects on rep are all coming from a <i>single</i> posting. That’s skewed, because <i>users on the site are more likely to see higher-voted questions and answers than they are to see lower-voted ones.</i> That’s simply how the search facilities work by default: understandably and helpfully, users get to see highly-regarded content before they see the dregs of the site. But this means that highly-upvoted content will always get more exposure, and therefore continuously be exposed to more upvotes, while downvoted content will get less exposure and less downvotes. <i>This skewness is disproportionately rewarding the experts and inflating their rep.</i></p> <p>Let’s ignore the downvoted content for a second and think about the upvoted content: it is continuously getting upvoted, <i>just for being there.</i> Meanwhile, the person who posted that content could very well have not made a single contribution after that (taking this to the logical extreme). That’s an unfair advantage, and thus a bad indicator of that person’s cred in the community.</p> <p>It’s clear at this point that the SO rep system is not going to be recalibrated yet again (barring some really drastic decision) to fix this bias, so let’s imagine for a second what a rep system would look like that actually <i>did</i> fix it. My idea is that such a rep system would reward (or punish) a user for a single contribution by <i>a single point only,</i> to be determined as the net number of up (or down) votes. So, if a post had +1 and -1, the reward to the contributor is nothing. If the post has +100 and -12, the reward to the contributor is +1. And if the post has +3 and -5, the reward is -1. If there’s a tie, the next person who comes along has the power to break that tie and thus ‘reward’ or ‘punish’ the contributor. Usually, of course, the situation won’t be a tie–usually there’s pretty good consensus about whether a contribution is good or not (to verify this, simply log in to Stack Overflow and click on the score of any question or answer on the question’s page–it’ll show you the upvotes and downvotes separately).</p> <p>The sum of the net effect on reputation from each of a contributor’s posts shouldn’t become the final measure of their profile rep, though. That doesn’t give the community an easy way to tell apart a person with +100/-99 rep (a polarising figure) from someone with +1/0 (a beginner, an almost-unknown). Instead, users should be able to judge contributions as +1 (helpful), -1 (not helpful), or 0 (undecided). And each net reputation change from a contribution should form a part of a triune measure of rep: <i>percentage helpful, percentage not helpful, and percentage undecided.</i></p> <p>The three parts of the measure are equally important here. The vote on the merit of a contribution is nothing but a survey; and any statistician will tell you that in a survey question you <em>must</em> offer the respondent the choice of giving a ‘Don’t know’ answer. In this case that’s the ‘undecided’ option. If we don’t offer this option, we are missing critical information about the response to the contribution–we can’t tell apart people who simply <em>didn’t vote,</em> or those who tried to <em>express their uncertainty</em> in the question/answer by not voting.</p> <p>This way, everyone immediately sees how often a particular user contributes valuable content, as opposed to unhelpful or dubious content. And the primary measure of rep is therefore not something that can grow in an unbounded way: the most anyone can ever achieve is 100% helpfulness. That too, I think, should be quite rare. The best contributors will naturally tend to have higher helpfulness percentages, but it won’t so much a rat race but rather a level marker within the community, tempered by their levels of ‘unhelpfulness’ or people’s indecision about their contributions.</p> <p>So much for user profile rep. I do think that the scores on questions and answers should behave in the traditional SO way: all votes should be counted as individual votes, instead of (as with user profile rep) being summed into a net positive/negative/undecided vote. The reason for the difference is that the votes are the measure of each contribution’s merit; and if (for example) you have two similar contributions, their vote scores should be a good way to judge between them. Again, vote score should be presented in the form of a three-fold percentage measure of helpfulness, unhelpfulness, and undecidedness (with vote counts available on, say, mouseover). This keeps conformity with user profile rep and puts an upper bound on the score shown on each question or answer. The reason why this is a good thing is that most of the time, to a site user, unbounded scores are simply extra information they won’t really process. The site itself can easily search and present content in order of most highly-voted; but the reader just needs to judge merit on a fixed scale. Anything extra is just cognitive burden on the reader.</p> <p>So to recap, if we’re to implement an <i>unbiased</i> user profile rep, we need to count the net helpfulness of each contribution <i>once only.</i> But for content scoring, we can count each vote individually. And to present everything in a uniform way and with low cognitive burden, we should show all scores as a three-fold measure of percentage helpfulness, unhelpfulness, and undecidedness.</p> <p>Once we have this system in place, we can start doing interesting things, like automatically closing questions which sink below a threshold of, say, 10% helpfulness (they’ll start out with 100% helpfulness because the original asker’s vote is automatically counted as helpful–otherwise they wouldn’t have asked). And we can do away with reputation loss from downvoting, since a downvote will usually have no effect on the recipient’s profile rep, and only one unit of negative effect on the contribution being downvoted.</p> <p>Achieving an unbiased measure of rep is tricky. But I think we can do better than SO’s current system by rebalancing the ‘rewards’ and ‘punishments’, and bounding the primary measures between 0 and 100% helpfulness so that we don’t end up with another Jon Skeet on our hands (I kid–Jon Skeet is great :-)</p> Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-58185281891600494162013-12-09T11:41:00.001+08:002013-12-09T11:41:23.617+08:00Man of Steel<p>IT TOOK me a while to write about Zack Snyder’s <em>Man of Steel</em> (MoS) because I was trying to articulate what it meant to me. And I think I’ve got it: MoS is our generation’s Superman anthem.</p> <p>Let me explain. The Donner movies* were an anthem of the previous generation: Clark Kent as the Everyman, Superman as the benevolent big Boy Scout. Snyder has reimagined Clark as an outsider trying to find himself, someone who’s a little lost in the world. And a lot of us can relate to that, especially in this post-recession age.</p> <p>With MoS, Snyder and Zimmer have quite literally given us an anthem for this era: brash, bold, perhaps worlds-spanning. And with it, there’s the wild element of of danger and uncertainty because Clark still doesn’t have full control over his powers, his emotions, and his moral compass yet.</p> <p>Speaking of moral compass, I honestly don’t have a problem with the way it ended with Zod. There’s precedent for it in the comics, and I felt it was a nod to that. My problem was with the way they used Metropolis as the Kryptonian battleground. And maybe I’m being overly sentimental here, but I would’ve thought that Clark would try his hardest to keep those things happening to densely-populated urban centres, especially Metropolis. But then again, maybe it just goes to show how we’re not in Kansas any more, in terms of who and what this Superman is. It’s a brave new world.</p> <p>* I count <em>Superman Returns</em> as one of the Donner movies because it explicitly tried to follow that continuity and approach to Superman/CK.</p> Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-86866441378032312682013-11-02T10:39:00.001+08:002013-11-02T10:39:01.587+08:00Notes on The Master and Margarita<p>‘MANUSCRIPTS don’t burn’.–Woland, The Master and Margarita</p> <p>Recently I re-read this classic, long my favourite book, and I re-discovered why that is. It always amazes me how Bulgakov changes his tone and phrasing, here switching to an everyday, very Russian dry humour and wit, and there to an almost science-fiction exposition. Some notes:</p> <p><em>‘… Let me see it.’ Woland held out his hand, palm up.</em></p> <p><em>‘Unfortunately, I cannot do that,’ replied the master, ‘because I burned it in the stove.’</em></p> <p><em>‘Forgive me, but I don’t believe you,’ Woland replied, ‘that cannot be: manuscripts don’t burn.’</em></p> <p>Ideas: the most incredible and indestructible creation of humankind. Once an idea is created, it can never be destroyed.</p> <p><em>‘No, because you’ll be afraid of me. It won’t be very easy for you to look me in the face now that you’ve killed him.’</em></p> <p><em>‘Quiet,’ replied Pilate. ‘Take some money.’</em></p> <p><em>Levi shook his head negatively, and the procurator went on:</em></p> <p><em>‘I know you consider yourself a disciple of Yeshua, but I can tell you that you learned nothing of what he taught you. For if you had, you would certainly take something from me. Bear in mind that before he died he said he did not blame anyone.’ Pilate raised a finger significantly, Pilate’s face was twitching. ‘And he himself would surely have taken something. You are cruel, and he was not cruel….’</em></p> <p>How incredible it would be to not be cruel and petty in this world.</p> <p><em>‘… You uttered your words as if you don’t acknowledge shadows, or evil either. Kindly consider the question: what would your good do if evil did not exist, and what would the earth look like if shadows disappeared from it? Shadows are cast by objects and people. … Do you want to skin the whole earth, tearing all the trees and living things off it, because of your fantasy of enjoying bare light? You’re a fool.’</em></p> <p>Ah, how clean-cut good and evil are to the Devil … on a grand scale, you need evil to balance out the good. Of course, this is ignoring the minutiae … maybe the Devil’s not in the details, but rather in the grand scheme of things?</p> <p><em>‘… If it is true that cowardice is the most grievous vice, then the dog at least is not guilty of it. Storms were the only thing the brave dog feared. Well, he who loves must share the lot of the one he loves.’</em></p> <p>An echo of the master and Margarita?</p> Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-83438266991589840802013-09-13T09:06:00.001+08:002016-11-14T12:01:00.833+08:00Excel Gotcha–Fractional NumbersTODAY I learned (the hard way) about a subtle bug in Microsoft Excel. It seems that to the VLOOKUP function looking for a matching value in a range, two equal fractional numbers are not always equal.<br />
Fractional numbers, technically known as floating-point numbers because of the way computers store them internally, sometimes give Excel a headache. If you want to see this for yourself, try out the following exercise:<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNQgLWpJrrTDR_rT3ostGv5CNxAijo4HhiuHM1BeM65K4AZuL4QNgmU8L4pW6vK6WR3jsttnRfJ8ZNOpWcTfwjCPu9corLwxgmGgzOPMjk7ZrBxPjHJrIRivgxJwZ2lHkWDhI/s1600-h/image%25255B14%25255D.png"><img alt="image" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNf5p1KkrrXYo7CXDBT5mQjLywWURh2ItWcbjrr4cbjXHIe4jUIoM4jGfePceWGwQEgFETW6zUEInfsIFj-RqNpg7xoa2Y4bi9Vj12QIPMWwqGSWHL7W79m_4UvdP02JCWCwg/?imgmax=800" height="248" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="423" /></a><br />
Edit: the formula above should be '=VLOOKUP(3.3, tblLookup, 2, <b>FALSE</b>)'.<br />
<br />
You will find yourself with the following error:<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvglMye6TmOxqA4fB-KA9yxcB8hrLQxJxhqm70JBXku92rzOa-pGVB_nHjHLaPLxv_sFRVK4m9Su8Y8Do5T6O_9-S_JWIXFhADoQmiCWMjbx6rkxdhjn1uQuNmg9BIQm9QG6M/s1600-h/image%25255B6%25255D.png"><img alt="image" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNiVd6T7zrGtnfRsklkI2Ud7gOySC2oKlLZ83Hu6j3SC7Ma0rczZAwfqo086FqpWjTZIjfpjqtoDBHTL3qzT0E6hYkd5gYYu0oTFcmpfugOep3JSt3CbOndSLodnldZgB9EXc/?imgmax=800" height="228" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="223" /></a><br />
Even more nefariously, if you use the range lookup option:<br />
=VLOOKUP(3.3, tblLookup, 2, <strong>TRUE</strong>)<br />
Excel will give you an actively incorrect result:<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjLgv_oVYZiZGjskNFxovrYxABDRc1lNHkaaLkvY6CB-zkEzoGClTR6EUv-flkZRIUo2D3dHP0otQqVR3aC5hKtGbZPZbkMBxb2VHPehJClxlpF60EHVGZy3d3cF3cQZu0pUQ/s1600-h/image%25255B21%25255D.png"><img alt="image" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsR3SUzKL4V0HImLVgcUl93cCGPZ6xwD73dz2jxwaoacYwfLT3ywlPH5jgjLs_o1-zoNlv4jOStlj0CPWxvz-HHFgtkYrcdPKExX2AEEbfjKaQd0pTYcRz0rdjDirFeMD0sBw/?imgmax=800" height="235" style="background-image: none; border-bottom: 0px; border-left: 0px; border-right: 0px; border-top: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="473" /></a><br />
So, be extremely wary of using fractional numbers as lookup keys in VLOOKUP functions. If you must, then use the techniques described in Microsoft’s <a href="http://support.microsoft.com/kb/315961">Knowledge Base article</a> on this issue.Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-49941764057720217402012-12-10T13:41:00.001+08:002012-12-10T13:43:49.419+08:00Analysing Transit Spending with Presto<p>ABOUT a year ago roughly I started using a new transit fare payment card called <a href="https://www.prestocard.ca/en/">Presto</a>. Presto is a top-up card–you pay as you spend–and it promised to unify fare payments for public transit systems throughout the Greater Toronto Area. By and large, it has lived up to its promise. But it does have its fair share of discontents.</p> <p>One of the things that I was impressed by when I first got set up and registered on their website was they have a table of raw data on your transit usage–what service was used, where you travelled from, date and time, amount paid, etc. It was limited to only the past three months’ worth of data, though. No problem, I thought. I’ll just log in every three months, copy the accrued data into an Excel file, and save it that way. And for the most part it worked.</p> <p>With this raw data, I imagined that I’d be able to do analysis on things like my travel patterns, bus timings (e.g. if some are regularly late), and of course how much I’m spending per week/month compared to how much I’d be spending with more conventional tickets or weekly/monthly passes.</p> <p>I made a mistake, though. When copying and saving the data in a nicely formatted Excel file, I didn’t notice that Excel wasn’t properly understanding the date format (dd/mm/yyyy) used in the data and was converting it into bogus dates, for whatever reason. And so I deleted some (to me) extraneous columns in the data, like another column which contained the month in which the transaction took place. So I ended up not being able to do month-to-month-type analyses on a large subset of the original data.</p> <p>Having learned my lesson, I’ve taken care to not delete any more columns in the fresh data I’m copying down now–just formatting things like transaction times and months when I’m absolutely sure Excel is understanding them properly.</p> <p>With the new, better, data I managed to do a spending analysis like I originally wanted. And though I’d been a bit sceptical of the savings with Presto for me personally, I became a believer after seeing the figures below.</p> <p>Before I get into the analysis though, a quick explanation of exactly how payment with Presto works: when you first buy the card at a transit kiosk, you pay some amount out of pocket for them to load the card with initially. When you board a bus/train, you tap the Presto card on a special reader and it deducts the amount of the fare from the card. Then you periodically top up the card to prevent going down to zero balance. You can set it up to automatically charge your credit card a certain amount when the Presto balance reaches a certain lower threshold that you set. This is really convenient and I’ve set up mine to auto-load $40 when the balances goes down to $20.</p> <p>One more thing to keep in mind before the analysis: all of these months were more or less full working months for me, in which I worked at least 20 days and therefore took at least 40 transit rides throughout the month.</p> <p><strong>The Analysis Result</strong></p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHNTtSe8B-GuxUCEuTsKPhWw8_CMnDF7md4nbD5YNZbEvgwJBxZkPwZbeGIRt6dJ4AiaqxRfe1Xy5s54e8hUPjuwcOtu04S8NbZPjeG32sCbV8Z7rH0t9TgSvI_2M5YJzJ8pU/s1600-h/image%25255B25%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhojBpUuW7yR5j_DD3XfaDGwksd9WiTTKY3FQH092c6qACBJNRP6MRpdDZLrgONU-A9K4zyFuSyly8qqWWqsm1HFavD3OLZJwaLcvXi0xGF7V9Jkh95mg8sq8uRRZJnK9Ro_sg/?imgmax=800" width="439" height="131" /></a></p> <p>The above screenshot shows an Excel PivotTable with one line entry per month. So to go through the figures for September: the ‘E-Purse Fare Payment’ column says I spent $89.96 in transit fare in September; ‘E-Purse Load Value’ says my credit card was charged $80 total throughout September and that balance was added to my Presto card; and the ‘Grand Total’ of -$9.96, being negative, means I actually spent about $10 more than I loaded onto the card that month (since I had some balance left over from August). And so on for the following months.</p> <p>How does this compare to what I would have spent with the more conventional weekly or monthly passes? Mississauga Transit, or <a href="http://www.mississauga.ca/portal/miway/busfares">MiWay</a> weekly passes are $29, so for a month’s worth of them I’d have spent roughly $116, give or take a few days. For a monthly pass I’d have spent $120. Now these are basically the most affordable options if you need to ride 40 times throughout the month. You can’t get cheaper than that if you’re working full-time.</p> <p>Given the above, September was really a very good month–lot of savings. My credit card was charged only $80. October was not so great, but not exactly horrible. Note that my credit card was still only charged $120–the extra $2.80 was from someone who borrowed the card and loaded some money into it by accident. This is no more than a monthly pass, and now let me explain why the spend was greater in October:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4fYR30dqVg5OpLMFZ1XchFJ3Pc0Pn-ChniPLuj59Q0KQvR9LOgRb0LpScRkRvvU6aQTVlDzdFK5V2uYWLCHoJUTD3EprK1LXmK-pdfIEWanrsXE9BbJq-KjQKpIYi7bP6ZO4/s1600-h/image%25255B26%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjNxRNzxOxx3thDV1WRPrR03LoHuvDA_B2ByuGwK5dGoDEkpF5liUgM0SdMLNa3NpJ4Ir5kCK6cSC50GvDcj68bDI_TbAjvFPLpmDKd6LIbVod67p5WqTBEfP6O1ffRd2OuD4/?imgmax=800" width="462" height="259" /></a></p> <p>The above screenshot shows the same PivotTable as before, just broken down by transit system.</p> <p>The person who borrowed my card spent about $11 on GO Transit, leaving $117 for my regular travel to/from work, and other places. Still competitive with the weekly and monthly passes.</p> <p>November was competitive at a spend of $114.37–less than the MiWay weekly/monthly passes despite some extra travel on other transit systems. Again, my credit card was charged exactly $120. The remaining $5.63 was carried over as balance into December–something that is simply not possible with monthly/weekly passes.</p> <p>December is so far so good. Presto has automatically reloaded early in the month, so for now the credit card has been charged a bit more than I’ve spent on transit this month. But that will have evened out by the time December ends.</p> <p>All in all, a lot of value for money and a bunch of other benefits (check out the <a href="https://www.prestocard.ca/en/">Presto</a> website for details).</p> <p><strong>Process</strong></p> <p>The steps from raw Presto usage data to finished PivotTable are fairly simple–if you’re an Excel user, you should be able to mostly figure it out. But the really quick summary: log in to the Presto website, go to the transactions page, show all transactions from the past three months, drag-select (with the mouse) the entire transactions table (including column headings) and paste into Excel. Excel should understand the tabular format and get it more or less right. Get rid of all formatting, then convert the range to an Excel table (select any cell in the data, press Ctrl-T). Format the ‘Loyalty Month’ column (should be column H) with the custom ‘number’ format <strong>yyyy-mm.</strong> This uniquely identifies the month and year. Finally, create a PivotTable from this raw data with the following specifications:</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOCSEX9V-lhij6NihpgfGONnLa2SqPOq5gDMRF2jqrwjfwYkWvJH3wzXsaTpeaWTLVnh_kleR7iLC9u-W5MzIj3o2NvdQUiu3jVNhTVD2tqUjKMFDMomCEcxvOinABHAcyFSk/s1600-h/image%25255B24%25255D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMFxHhZ8MIe4Cdsr89st4jBesT_8gknlrE-LkATwzNcMJo5F23cZe-h7HnGfcZ_HHjVy7aHd4UcjAUwotFPxNiDUK74QjuWlM0BxWe81eDg1IwbiJmwdUKh7WnQyJFHB4VSJM/?imgmax=800" width="328" height="305" /></a></p> <p>Happy analysis <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj7CgwupMztMrPGUm1oH_g15i_7pSWa2HgSj_MNXCIVvm_ezbgN0o-4SLwGCEsXuPqUjtAuKwlY7VudKimcoQ4U5vZjoA9dDs3cpyIu-lOCTbiKVzWFENEdiq16jHrv5q7khg/?imgmax=800" /></p> Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-75203662200788333782012-12-08T14:12:00.001+08:002012-12-08T14:12:19.383+08:00Tweet from the Browser Address Bar<p>This will work on Firefox and should also work on Chrome with a little adjustment. You can start posting a tweet straight from the browser address bar instead of having to navigate to the Twitter website and click on the new tweet button.</p> <p>In Firefox, create a new bookmark with the following properties:</p> <p><strong>Name:</strong> Tweet (or similar)</p> <p><strong>Location:</strong> <a title="https://twitter.com/intent/tweet?source=webclient&text=%s" href="https://twitter.com/intent/tweet?source=webclient&text=%s">https://twitter.com/intent/tweet?source=webclient&text=%s</a></p> <p><strong>Keyword:</strong> tw (or whatever you like)</p> <p><strong>Description:</strong> Tweet something</p> <p>Now, with this bookmark saved, go to the address bar and type: <strong>tw Just testing.</strong> Then press <strong>Enter.</strong> A new tweet composition page should show up with the words <strong>Just testing.</strong> Finish off the tweet as wanted and click <strong>Tweet.</strong></p> <p>Is the tweet composition page unavoidable? Maybe not, but I don’t see an easy way to tweet directly from the address bar. And maybe that’s for the best–giving you a chance to finalise things before you publish for the world to see.</p> Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-20978697659938970902012-05-21T05:01:00.001+08:002012-05-21T10:52:08.807+08:00Marvel’s The Avengers<p><em>Warning: Minor spoilers. I do references specific scenes from the movie, but nothing major.</em></p> <p>HARK, True Believers, and let me tell you a story. It’s a simple story, one of raw power and potential, where Good comes together against Evil and drives it back for another day. It’s the original story of the Avengers, straight from their first appearance in comics.</p> <p>There came a day (unlike any other), when Loki, the Norse god of mischief, unleashed a series of machinations, starting with a clash between the Hulk and Thor. Other heroes got involved by chance or by fate, figured out what was going on, and finally stopped him. On that day they came together as a team, and the Avengers were born.</p> <p>Since those original comics came out, there’ve been many iterations of the story. Significantly, there was Mark Millar and Bryan Hitch’s <a href="http://en.wikipedia.org/wiki/The_Ultimates">The Ultimates</a>, the Ultimate Marvel version of The Avengers. It even provided the source material for the enemy alien armada in the movie, the Chitauri. In a way, The Ultimates was the kick in the pants that started the whole Marvel Avengers movie franchise rolling. So given all that history, where does this movie stand?</p> <p>First of all, its credentials are impeccable. The story has Joss Whedon’s imprint all over it—the snarky humour, the really fun moments, the horror and the Big Bad (and the hints of the Bigger Bad). Oh, and let’s not forget the destruction of, and escape from, the SHIELD base in the beginning—a nod to the destruction of the Hellmouth in the series finale of Whedon’s <em>Buffy the Vampire Slayer</em>. That was awesome <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTTFx0KNCt3bvWcndV0xzsoW8TKRwlHMbM-OOwod3ehJ4Nw_obCkFO7BAyXiPuA-ZLffyXVzgN2nc6pBRAMS6IL-Ysut5oJYtlnhJ0uEj6uhF5e5ahehOqj2FuBlkxEs0gbxE/?imgmax=800" /></p> <p>The screenplay is by Zak Penn, who’s done really good work recently—to me, most notably in his new (and returning) show <em><a href="http://www.imdb.com/title/tt1183865/">Alphas</a></em>, which is like a modern, grounded-in-reality version of <em>X-MEN</em>.</p> <p>The ensemble cast plays really well off of each other, in a way a lot of ensembles haven’t been able to; their egos and personalities, their senses of humour and honour, shine through; and under Whedon’s guiding hand, through all their neuroses and bickering, they keep a laser-like focus on driving the story forward.</p> <p>The story: there were many moments that were laugh-out-loud funny—e.g. when Captain America shows a bunch of hardened NYC cops why they should take orders from him. There were moments when I cheered—e.g. when Iron Man shows up in Stuttgart to take down Loki. Robert Downey Jr’s Tony Stark provides the attitude and AC/DC’s <em>Shoot to Thrill</em> provides the soundtrack. Awesome! <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTTFx0KNCt3bvWcndV0xzsoW8TKRwlHMbM-OOwod3ehJ4Nw_obCkFO7BAyXiPuA-ZLffyXVzgN2nc6pBRAMS6IL-Ysut5oJYtlnhJ0uEj6uhF5e5ahehOqj2FuBlkxEs0gbxE/?imgmax=800" /></p> <p>On a side note, when they first announced the original Iron Man movie, I was rooting for Leonardo DiCaprio to play Tony Stark. The character was literally based off Howard Hughes (notice how Tony Stark father’s name is Howard) and DiCaprio had proven he could pull off Howard Hughes. But three movies later, I’m solidly in the RDJr camp. He’s proven himself, and not just because of the moments when he’s funny and eccentric, but especially in the moments when he’s dead serious.</p> <p>As for the characters: I won’t do a headcount (I’ll let Tony Stark <a href="http://www.youtube.com/watch?v=OCYg4f77Eqo">do that</a>), but it’s being said that Mark Ruffalo’s Bruce Banner/Hulk provided the heart of the movie. Absolutely true. The wry humour and sarcasm, the world-weary cynic mixed with the eager scientist playing with new gadgets, Ruffalo’s Banner shows us all these sides of the character. As the Hulk, he shows us something almost elemental: rage personified, quick and unexpected as lightning, a force of nature, but ultimately a personality, a man struggling to do what’s right through the thick red haze of anger.</p> <p>There was plenty of meat in all the characters; there were moments that showed that Joss Whedon <em>gets</em> them all. Take Captain America, Steve Rogers. A man who must feel like he’s suddenly time-travelled 70 years into the future, he’s looking for anything that’ll give him a connection to the past and the present. He doesn’t get most of the pop-culture references spouted off rapid-fire by the rest of the Avengers and SHIELD agents, but when he does, he has one of those ‘A-ha!’ moments that tell him this is still his own world.</p> <p>Take Tony Stark. What’s the first thing this cynical technologist does when he comes aboard the SHIELD Helicarrier, Nick Fury’s flying fortress and repository of some of the best-kept secrets outside the Vatican? His actions are so quintessentially <em>Tony Stark,</em> they’re almost predictable.</p> <p>Take the Black Widow. Much of her past is a mystery. In the comics, she’s a lot like a Russian version of Wolverine, given what was done to her by her government. She’s someone who’s trying to make amends; she’s a master spy—clever enough to outwit the god of mischief at his own game. All of these things are hinted at, and shown in her scenes. Every scene she’s given is used to the <em>maximum.</em></p> <p>And of course, take Loki. Disgruntled, and carrying a grievance the size of a kingdom, Loki comes to Earth with a plan to take away the world his brother loves and protects. He wants to ‘free’ people from the ‘tyranny’ of freedom—brilliant and twisted; something only Loki’s warped mind could conceive. The size of his ego, and his giant psychotic need for recognition, are such that one after the other, the Avengers and SHIELD big guns profile him and start figuring out his plays. Agent Coulson delivers what I think is <em>the</em> best line in the movie (and that’s saying something) when he explains to Loki why he won’t win.</p> <p>If there was one character whose essence didn’t come out in the movie, I’d have to say it was Maria Hill. I know a lot of fans were excited to see this relatively new character (in the comics) make the transition to the big screen for the first time, but Maria Hill is literally supposed to have learned spycraft and attitude at the Nick Fury school of badass; she wasn’t really given an opportunity to show that here, maybe given the fact that Agent Coulson seemed to be performing the second-in-command duties in this movie. Oh well, maybe in the next one.</p> <p>Speaking of Nick Fury’s second-in-command, one character who was rather conspicuously missing from this iteration of SHIELD was Dum-Dum Dugan; especially given that he’d been in the Captain America movie of last year. I guess they would have had a hard time explaining Dugan’s (and then Fury’s) seeming eternal youth (or at least their eternal non-retirement), something they still haven’t explained in the main Marvel comics storyline, as far as I’m aware.</p> <p>I’ll skip the main plotline and results (the Avengers save the day, what’d you expect), and jump to the delicious little end-of-credits teaser. Let me take a moment here to cackle madly with glee while I tell you, True Believers, that if they carry through with what they’ve shown there (and history says they will), then the Avengers will be going intergalactic, interdimensional, inter-timeline and possibly exploring the boundaries between life and death! *cackle*</p> <p><em>Verdict: Loved it. And Long Live Joss Whedon!</em></p> Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-30220563704474291222012-05-06T11:42:00.000+08:002012-05-08T11:17:51.048+08:00Bookmarking in Adobe ReaderI RECENTLY moved to Windows and started using Adobe Reader. The latest version is Adobe Reader X (that is, 10) and I started to keenly feel the need for a bookmarking feature like the one that's built in to Mac OS’s PDF reader, Preview. (Which is quite superbly done.) <br /> <br />A quick run through Reader's menus revealed nothing about bookmarking. Adobe's still calling the built-in navigation links in PDF documents ‘bookmarks’. So that’s a dead trail. A web search turned up a bunch of hacks, some of which work but not very well, and others which just don’t. <br /> <br />Fortunately, Adobe Reader X has a (no hacking required) feature that’s almost equivalent to bookmarking, albeit in a slightly unexpected place: the <b>Comment</b> panel on the right-hand side. If you click the <b>Comment</b> toolbar button on the right, the <b>Comment</b> panel pops up, divided into two sections: <b>Annotations</b>, and <b>Comments List</b>. <br /> <br />So to add a ‘bookmark’: click the <b>Sticky Note</b> button in the <b>Annotations</b> section of the panel, then click anywhere on the page where you want to position the sticky note. You can then minimise the sticky note by clicking the minimise button on its upper-right corner. <br /> <br />As soon as you place a sticky note on the page, it shows up on the <b>Comments List</b> section of the panel. This is awesome because this comments list can basically be used like a bookmarks list, with a click on each comment taking you to the exact page it’s on. And when you’re done with it as a bookmark, you can right-click on it and select <b>Delete</b>. <br /> <br />There is one drawback: every time you close the PDF file, you’ll have to save it, in place, again. The sticky notes, or for our purposes bookmarks, are saved inside the PDF files, and Adobe Reader doesn’t let you just <b>Ctrl+S</b> save a PDF file, it forces you to pick the file in a <b>Save As</b> dialog box each time. Still ... that’s a relatively small trade-off for a pretty convenient bookmarking feature. Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-41689503508301822972012-02-13T08:16:00.000+08:002012-02-13T08:17:20.502+08:00Short Note on Blogging<br />
SOME time ago I <a href="http://yawar.blogspot.com/2010/03/blogging-sensitive-stuff-and-some.html">complained</a> that there wasn’t any good, free blogging software on the Mac. Well, since then I’ve pruned my list of demands somewhat, and learned to settle for some typographical niceties like curly quotes (‘’, “”) and en-dashes (–).<br />
<br />
And it turns out that the Mac’s built-in TextEdit editor does these nicely, with a little help from the system-wide Substitutions feature (in TextEdit’s main menu, click Edit > Substitutions > Show Substitutions, and check all the automatic substitutions offered there).<br />
<br />
So now it’s just a matter of typing out my thoughts in TextEdit, which laods almost instantly; and dealing with the psychological baggage of navigating to the correct post page in Blogger comes later.Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-77905459065128350172012-02-12T15:31:00.004+08:002012-02-12T15:31:52.373+08:00Thoughts on Lion<br />
I UPGRADED to Mac OS X Lion, the latest and greatest version of Mac OS X, tonight. While the update was cheap ($30) and easy (click and run), it was also slow. Roughly speaking it must have taken at least a couple of hours to finish up. At the end of that, though, I found all my files and settings transferred seamlessly into the new OS.<br />
<br />
The first question on my mind was whether Lion would slow down my system, given that I have a basic 2009 MacBook. The answer is no; it performs just as well as Snow Leopard in my perception.<br />
<br />
On first boot there’s a change right from the start: the login screen is now a single page, not a window, of users and basic system info like battery status, time and Wi-Fi status. And on login the desktop is kind of sent hurtling forward towards you–it seems like Apple has grown fond of the kind of page-transition animations that started out on iOS.<br />
<br />
Some of the biggest new features you see right after logging in are Mission Control and Launchpad. Mission Control (shortcut key Ctrl-UpArrow) is basically a new version of Exposé; and Launchpad is like the iOS app launcher–all your applications arranged in grids of icons, ready to be launched with a click. I like the former; but I don’t really intend to use the latter much because my most frequently-used apps are on the Dashboard, or I just launch them with Spotlight.<br />
<br />
There are numerous new features scattered throughout the system; for a complete list see <a href="http://www.apple.com/macosx/whats-new/features.html">Apple’s page</a>. I want to touch on a few of the UI changes.<br />
<br />
The first is the look of basic UI elements like buttons, drop-down lists, checkboxes, etc. These are all now rounded rectangles instead of bubble-shaped. That’s definitely a break from the OS X Aqua design that was introduced ten years ago.<br />
<br />
The second is the new overlay scroll bars that disappear when you’re not actually scrolling, thus giving you back some screen real estate. This is definitely influenced by iOS–designers had to figure out new space-saving tricks on mobile form factors and these tricks are now showing up on more traditional desktops. However, the new scroll bars aren’t actually enabled by default. In the System Preferences, General page, the ’Show scroll bars:’ option is originally set to ‘Automatically based on input device’, which basically means, ‘depends’. To enable the overlay scroll bars, choose the ‘When scrolling’ option here.<br />
<br />
Also, another surprising (and slightly annoying) change is when scrolling with a wheel mouse, the traditional wheel down movement actually scrolls stuff <i>up</i> and the wheel up movement scrolls stuff <i>down.</i> To fix this, uncheck the ‘Move content in the direction of finger movement when scrolling or navigating’ option in the ‘Mouse’ page.<br />
<br />
There are a couple of big changes in apps I use frequently. Mail has been redesigned to show all messages in the same conversation on a single page, like Gmail. For this I’m grateful. However, the ordering of the messages in the conversation view is most recent first–for me, that’s upside-down. This can be fixed in Mail Preferences, the Viewing page, in the ‘View conversations:’ section, by unchecking the ‘Show most recent message at the top’ option.<br />
<br />
Another change is that the Address Book app has been redesigned to look like an actual open book with a list of contacts on the left and a detailed view of the contact on the right. I liked the old, normal Cocoa UI; to me the new design looks a bit cartoonish, and amateurish. The functionality is still the same, though. One thing I’ve always found puzzling that would be nice to get off my chest: all the operations on a card (a contact) are in the ‘Card’ menu, except for ‘Delete Card’, which is in the ‘Edit’ menu. Baffling.<br />
<br />
Another couple of interesting (to me :-) tidbits: Lion has FaceTime calling built-in, and Google Chrome now takes advantage of Lion’s new support for full-screen mode instead of baking in its own.<br />
<br />
So bottom line: Lion continues the evolution of Mac OS into something more iOS-like, but mostly familiar and comfortable for OS X users. Plus, it’s much easier to say ‘Lion’ than ‘Snow Leopard’, so that’s a win right there. :-)<br />Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0tag:blogger.com,1999:blog-6925752.post-69311744247454288532011-11-10T12:19:00.001+08:002011-11-10T13:16:14.110+08:00Kobo VoxTHE <a href="http://www.kobobooks.com/kobovox">KOBO Vox</a> (from Latin, vox populi, ‘voice of the people’) is Kobo’s latest and greatest ebook reader. It’s basically a touch-screen Android tablet, but Kobo has made some smart trade-offs to keep it at the $200 price point. Here are my impressions.<br />
<br />
<b>First Boot</b><br />
<br />
The first time it starts, the device asks to connect to a wireless network and then downloads and installs a software update. It then guides you through restarting and completing setup. You have to pick your time and date and then log in to, or create, a Kobo account. There don’t seem to be any options for not signing in to a Kobo account–to use the Vox, you must be signed in.<br />
<br />
<b>Hardware</b><br />
<br />
There’s much to like about this compact device. It’s roughly three-quarters the size of an iPad, and has a crisp full-colour screen. Text is crisp and images really pop out. It’s a little heavy to hold; could get uncomfortable over extended periods reading while sitting or lying down.<br />
<br />
The processor is not the most powerful you can fit into this form factor; but going for a slightly cheaper CPU is one of the trade-offs I mentioned, and ultimately I think worth it. I’ll explain more later.<br />
<br />
There’s a single speaker built-in with sound quality similar to that of a smartphone. No microphone or camera–so there’s no scope for voice or video chatting. And in terms of connectivity, there’s Wi-Fi, an SD card slot and a USB port, but no Bluetooth.<br />
<br />
<b>Software</b><br />
<br />
The Vox comes with Google’s Android OS 2.3 with a few relatively minor adjustments: the default home screen has a large Kobo desktop widget showing the covers of the five most recently-read books; the global pop-down notification list has been replaced with Kobo’s Reading Life stats (more on Reading Life later); and apparently you can’t access the Android Market because the device doesn’t (yet) pass Android hardware certification. There is an alternative app store called GetJar bundled.<br />
<br />
Since the Vox isn’t locked in to the Android Market, you can actually install any apps (*.apk files) you can find floating around on the internet. So the keyword here is caution–there’s plenty of malware out there for Android. I installed a couple of essential apps from <a href="http://goodereader.com/blog/electronic-readers/essential-kobo-vox-apps-and-tools/">a relatively trusted source</a>. The first is Overdrive, an ebook and audiobook app for DRM-protected books. Overdrive lets you connect to public libraries’ electronic catalogues and download books from them. I’ve successfully downloaded a couple of ebooks from my local library.<br />
<br />
The browser doesn’t come with Flash installed. It’s possible to install it from <a href="http://goodereader.com/blog/electronic-readers/essential-kobo-vox-apps-and-tools/">Good eReader's list</a> but I haven’t so far because from what I’ve heard, Flash is a mobile device killer. Even my laptop has a hard time with it.<br />
<br />
There’s a YouTube app that works pretty much as expected; a music and video player that I haven’t tried yet; and a few other apps that I haven’t actually bothered to explore–a Facebook news feed widget for the desktop, and other similar apps that plug in to Facebook. If I could uninstall these, I would; but there doesn’t seem to be any way to uninstall apps yet.<br />
<br />
<img alt="Kobo Vox customised home screen" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8fB8hI9Ye6FYX38b7CHngoLAGojMRHINvMMX6nszndLiyZzp58y6Eaya4XKFBjaSGo6RWFNIavDs6vMVF3mOn64ywWk9ckcYDqwJTD7lhgrcE5e8bc0aeWGc4dzme_6btfuU/" style="display: block; margin-left: auto; margin-right: auto; vertical-align: middle;" width="300" /><br />
<br />
<b>Reading eBooks</b><br />
<br />
One of the Vox’s biggest selling points is that it has a new ‘social reading’ feature called Reading Life. Reading Life lets you keep track of how many books you’ve read and how long you spent reading them; gives you ‘awards’ for finishing books; and lets you share these awards and statistics with friends. Newly introduced with the Vox is a comment feature called ‘Pulse’ that lets you publicly ‘like’ and share comments on specific pages of books you’re reading.<br />
<br />
Reading Life is pervasive and easily accessible from several places in the Vox interface–the pull-down notification area at the top; the dock at the bottom; and from the Kobo reading and library app itself. This gives a feeling of coherence to the device and makes it feel more like an ebook reader than just a generic Android tablet.<br />
<br />
However, you’ll only find yourself using Reading Life if you read ebooks on Kobo’s own ebook reader app. This would include reading books that you bought or downloaded for free from the Kobo store; and any books that you manually copied over from another device. If, like me, your main source of books is your public library’s electronic catalogue, you’ll probably end up using the Overdrive ebook reader app; and Overdrive is not integrated with Reading Life or Pulse.<br />
<br />
<img alt="Kobo Vox Overdrive ebook app" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7FOaGdtLP4ERZRli_19H9NV8sWuDvQElqkPPvkiZrK7tyrSg9mXslsucepuoiWDwAVzQfpKFx65Tad_eKAQ7b0xejStqhKwdIDvqc6jfzNipb5BVAUQEJET13kxb_UKKVO3o/" style="display: block; margin-left: auto; margin-right: auto;" width="300" /><br />
<br />
<b>Trade-offs</b><br />
<br />
So in general, how is the Vox as an Android tablet?<br />
<br />
A little under-powered. It runs most of the standard apps–browser, email, ebook readers–just fine. But when I tried to run a more graphics-intensive app, like the included free Scrabble, it more or less got stuck. I had to hard-reboot the device to get it up and running again.<br />
<br />
At the end of the day, the Vox is a compact Android OS-powered device that lets me read ebooks and just enough more that it’s a compelling buy.<br />
<br />Yawarhttp://www.blogger.com/profile/13741563704441932843noreply@blogger.com0