多言語サポートを進めるGeo3x3は、いろいろなプログラミング言語に触れる良い機会。 実装して貢献してもらった、関数型言語 Haskell、Elixir、Racket(LISP系) をベースに学び、OCaml、Erlang版を作りました。
下記はOCaml(オーキャムル)で作った、Geo3x3のエンコードとデコードです。手続き型言語からの移行用の優しさか、関数型っぽくない記述もありますが、ひとまず動作したので登録しています。 関数型言語、関数型的思考がだんだん掴めてくる間隔が楽しいので、何かの機会に遊んでみることをオススメします。大容量データ時代、超並列時代に使い所がありそうです!
open String;; let encode lat lng level = if level < 1 then "" else let (res, lng1) = if lng >= 0.0 then ("E", lng) else ("W", lng +. 180.0) in let lng2 = lng1 in let lat2 = (90.0 -. lat) in (* 0:the North Pole, 180:the South Pole *) let rec loop i lat lng unit = if i >= level then "" else let x = int_of_float (lng /. unit) in let y = int_of_float (lat /. unit) in let n = x + y * 3 + 1 in let lng2 = lng -. (float_of_int x) *. unit in let lat2 = lat -. (float_of_int y) *. unit in (string_of_int n) ^ (loop (i + 1) lat2 lng2 (unit /. 3.0)) in res ^ (loop 1 lat2 lng2 (180.0 /. 3.0));; let decode code = (* (35., 135., 14, 0.1);; *) let clen = String.length code in if clen < 1 then (0.0, 0.0, 0, 180.0) (* err *) else let c = code.[0] in let (flg, beg) = if c = '-' || c == 'W' then (true, 1) else if c == '+' || c == 'E' then (false, 1) else (false, 0) in let rec loop i lat lng level unit = if i >= clen then (lat, lng, level, unit) else let unit2 = unit /. 3.0 in let n = (int_of_char code.[i]) - 49 in (* ignore err check *) let lat2 = lat +. (float_of_int (n / 3)) *. unit2 in let lng2 = lng +. (float_of_int (n mod 3)) *. unit2 in loop (i + 1) lat2 lng2 (level + 1) unit2 in let (lat, lng, level, unit) = loop beg 0.0 0.0 1 180.0 in let lat2 = lat +. (unit /. 2.0) in let lng2 = lng +. (unit /. 2.0) in let lat3 = 90.0 -. lat2 in let lng3 = if flg then lng2 -. 180.0 else lng2 in (lat3, lng3, level, unit);;
29言語サポートまで増えた「Geo3x3」ですが、まだまだおもしろいプログラミング言語がいっぱいあります。 古の言語を使ってみたり、新しいプログラミング言語の使い心地を見てみるのにも活用できそう!