2018-12-20

(usocket): R6RS portable socket library

Motivation

When I wrote the MongoDB client library in R6RS portable manner, I have included socket procedures inside of the library. Now, I want to write Redis client, then I've noticed that it's very inconvenient that if there's no R6RS portable socket library. We have SRFI 106 for a socket library, however, it's not widely implemented especially on R6RS implementations. So I've decided to make it and it's here.

Portable R6RS socket library

Example

The library supports TCP and UDP client and server sockets. Most of the time, I only need TCP client, but it's nice to have in case it's needed. The very basic HTTP request call using this library would look like this:
(import (rnrs)
        (usocket))

(define client (make-tcp-client-usocket "google.com" "80"))
(put-bytevector 
 (client-usocket-output-port client)
  (string->utf8 "GET / HTTP/1.1\r\n\r\n"))

(utf8->string (get-bytevector-n (client-usocket-input-port client) 1024))
;; -> response from the server

(usocket-shutdown! client *usocket:shutdown-read&write*)
(usocket-close! client)
For portability, we don't provide any socket specific operation other than shutdown and close. Everything else needs to be done via input or output port.

Supporting implementations

The library supports the following implementation:
  • Sagittarius (0.9.4 or later)
  • Chez Scheme (v9.5)
  • Larceny (1.3)
Chez and Larceny require PFFI and psystem as their dependencies and they can only run POSIX environment (not on Windows, PR is always welcome :) ).

Who is using this?

As I mentioned above, I'm using this library to create R6RS portable Redis client. It's at least good enough to implement the client.

2018-12-02

SRFI-123の紹介

この記事は Lisp SETF Advent Calendar 2018 二日目の為に書かれました。

0x25歳になって最初に書く記事です(実際には投稿予約の機能を使っているので数日若いが…)。いい感じの区切りの歳の最初の記事としてはイマイチな題材かもしれないなぁとも思いつつ…

SRFI 123: Generic accessor and modifier operators は Taylan Ulrich Bayırlı/Kammer によって提唱された Gauche 風の総称アクセサを提供する SRFI です。取りあえず簡単な例を見てこれの何が嬉しいのかというのを確認してみましょう。
(import (rnrs) (srfi :123))

(define l (list (list 1) 2 3)) ;; Must not a literal list :)

(ref 1 0) ;; -> (1)
(ref* l 0 0) ;; -> 1
;; ~ is an alias of ref*
(~ l 0 0) ;; -> 1

(set! (ref l 1) 4)
(ref l 1) ;; -> 4

(set! (ref* l 0 0) 5)
(ref* l 0 0) ;; -> 5
こんな感じです。上記の例ではリストを使っていますが、その他のデータ又はレコード型でも似たような感じで動作します。

基本的にはref又はref*が適切なデータへのアクセス手続きに変換すると思えば良いです。上記の例ならば、reflist-refに変換しています。

set!は SRFI-17 を利用して実現しています。例えば以下のコード
(set! (ref l 1) 4)
(set! (ref* l 0 0) 5)
は、それぞれこのように変換されます
((setter ref) l 1 4)
((setter ref*) l 0 0 5)
ちなみに、SRFI-17 については LISP Library 365 で書いたSRFI-17の紹介を参照するといいかもしれません。

余談
この SRFI のポータブルな実装を覗くと、もの凄く頑張って色々なデータ型のサポートをしているのが見て取れます。この頑張りは総称函数があれば不用だろうなぁいう感じがするので、この SRFI の前に総称函数の SRFI があればよかったのではとも思ったりします(もしくは、Tiny CLOS を使って実装するとか?)。

 追記
(ref* 1 0 0)を修正(1:数字の一 -> l:小文字のL)