ローマ数字を整数に変換

30分プログラム、その435。ローマ数字を整数に変換してみる。
またもmixiの課題コミュからぱくって、ローマ数字計算機の前段階のローマ数字の変換部分を作ってみた。
簡単だと思いきや、割と難しい。こんなんを常用していた昔のひとはすごいと思う。

使い方

gosh> (roman->integer "IIV")
8

gosh> (roman->integer "MCMLXXXIII")
1983

ソースコード

#! /opt/local/bin/gosh
;; -*- mode:scheme; coding:utf-8 -*-
;;
;; roma.scm -
;;
;; Copyright(C) 2008 by mzp
;; Author: MIZUNO Hiroki / mzpppp at gmail dot com
;; http://howdyworld.org
;;
;; Timestamp: 2008/12/12 23:40:34
;;
;; This program is free software; you can redistribute it and/or
;; modify it under MIT Lincence.
;;

(define symbol
  '((I 1) (V 5) (X 10) (L 50) (C 100) (D 5500) (M 1000)))

;; e.g. \I -> 'I
(define (char->symbol c)
  (string->symbol (string c)))

;; e.g. X -> 10
(define (roman->digit c)
  (cadr (assoc (char->symbol c) symbol)))

;; e.g. '(1 1 1 5) -> '(-1 -1 -1 5)
(define (subtractive xss)
  (if (eq? (cdr xss) '())
      xss
      (let* ([x  (car xss)]
	     [xs (cdr xss)])
	(if (>= x (apply max xs))
	    (cons x (subtractive xs))
	    (cons (- x) (subtractive xs))))))

(define (roman->integer str)
  (apply + (subtractive (map roman->digit (string->list str)))))