temp_la :: Memo

https://twitter.com/temp_la

Scheme R7RS のパラメータオブジェクトはReaderモナドか?

SchemeのR7RSを読んでます。

R7RSからパラメータオブジェクトなるものが登場しています。(SRFI-39 からあるようです)

(define radix
  (make-parameter
   10
   (lambda (x)
     (if (and (exact-integer? x) (<= 2 x 16))
         x
         (error "invalid radix")))))

(define (f n) (number->string n (radix)))

(print (f 12)) ; ⇒ "12"                                                                           
(print (parameterize ((radix 2)) (f 12))) ; ⇒ "1100"                                                            
(print (f 12)) ; ⇒ "12"                                                                         
(print (parameterize ((radix 0)) (f 12))) ; ⇒ ERROR: invalid radix

要するに文脈によって(radix)の結果が異なる動作になります。

何となくReaderモナドとlocalという関数が似たような感じに見えました。

こんなふうに見える

module Main where

import           Control.Monad.Reader
import           Data.Char            (intToDigit)
import           Numeric              (showIntAtBase)

-- number->string                                                                                                                                                                                           
numberToString :: Int -> Int -> String
numberToString x rdx = showIntAtBase rdx intToDigit x ""

type Parameter = Either String Int

radix :: Parameter
radix = Right 10

radix' :: Int -> Parameter
radix' x
  | 2 <= x && x <= 16 = Right x
  | otherwise = Left "invalid radix"

--(define (f n) (number->string n (radix)))                                                                                                                                                                 
f :: Int -> Reader Parameter (Either String String)
f n = do
  rdx <- ask
  return $ numberToString n <$> rdx

main :: IO ()
main = do
  print $ runReader (f 12) radix -- Right "12"                                                                                                                                                              
  print $ runReader (local (const $ radix' 2) (f 12)) radix -- Right "1100"                                                                                                                                 
  print $ runReader (f 12) radix -- Right "12"                                                                                                                                                              
  print $ runReader (local (const $ radix' 0) (f 12)) radix -- Left "invalid radix"

完全に理解できてないのでここまでです。