kb84tkhrのブログ

何を書こうか考え中です あ、あと組織とは関係ないってやつです 個人的なやつ

「ちょっと残業」

っていうとき、実際どれくらい残業してるか、って業界とか会社とか人によって
かなり違いますよね

ウチの会社でも千差万別
働き方改革とは言いますがまだまだ残業が長い人も多いです

そういう私は以前はけっこう長かったんですが徐々に短くなってきたり
意図的に短くしたりしてけっこう短くなりました
といっても人によってはえーそんなに残業してるんすかみたいになると思います

何が言いたいかというと今日はちょっと残業でした

ゲーデルの不完全性定理の証明のアレをRacketで書いてみる (31)

さてTyped Racketもざっと見たので型をつけていってみます
動かせないのでテストもできませんでしたが
うまく型を付けられれば静的なチェックだけでもバグが見つかるのではと
(実際ときどき間違えてたし)

さてどんな型をつけましょうか
型っぽいものはゲーデル数、列、列の列、ですかね
型の関係としては自然数ゲーデル数>列>列の列という感じ
列の列は列でもある、とか列に含まれる、とか列の一種、とかそういう意味で

別の捉え方をすると記号、論理式、証明という型も考えられそうです
それぞれゲーデル数、列、列の列の一部となっています

で、そういったことをSubtypeで表現していけばいいかな、と思ったんですが
そういえばSubtypeを定義する式ってでてきたっけな?と思い当たりました
う、出てきてない
define-typeは既存の型に別名をつけるだけなので
ゲーデル数は数である、列はゲーデル数である、とやっても
結局ゲーデル数と数を区別することはできず
列を渡すべきところでゲーデル数を渡してしまった、みたいなことを
チェックすることはできそうにありません

しかしぐぐってみるとdefine-new-subtypeというのが出てきました
GuideではなくReferenceに掲載されていてしかもExperimental Featuresだと
むう
もっと基本的な機能かと思いましたが

リリースノートを確認してみたところRacket 6.3で実装されたようです
PLT SchemeのころからTyped Schemeっていうのがあったらしいことを考えると
比較的新しい機能なんですね

まあいいか
ではちょっと練習

#lang typed/racket

(define-new-subtype GNumber (gnumber Natural))
(define-new-subtype GSequence (gsequence GNumber))

(define c0 (gnumber 1))
(define s1 (gsequence (gnumber 2)))

(: number-func (-> Natural Natural))
(define (number-func x)
  (* x 2))

(number-func 0)
(number-func c0)
(number-func s1)

(: gnumber-func (-> GNumber GNumber))
(define (gnumber-func x)
  (gnumber (* x 3)))

; (gnumber-func 0) <- Error
(gnumber-func c0)
(gnumber-func s1)

(: sequence-func (-> GSequence GSequence))
(define (sequence-func x)
  (gsequence (gnumber (* x 4))))

;(sequence-func 0) <- Error
;(sequence-func c0) <- Error
(sequence-func s1)

やりたいことはできそうな感じがしてきました

Typed Racketのお勉強 (12)

7 Optimization in Typed Racket

Typed Racketは型の情報を活かして最適化を行います

  • 最適化を止めるには#lang typed/racket #:no-optimizeを使う
  • RealよりもFloatといったように、型を具体的に指定すると効果的
  • リストがnullでないことがわかっている場合は明示してやるとnullチェックが省略される

たとえば整数2個のリストだとわかっていれば

(: sum2 (-> (Listof Integer) Integer))
(define (sum2 l) (+ (car l) (cadr l)))

((Listof Integer)は0個以上のIntegerのリスト)
よりも

(: sum2 (-> (List Integer Integer) Integer))
(define (sum2 l) (+ (car l) (cadr l)))

の方がいいということですね
Vectorも同様
といってもStructでいいケースではStructを使ったほうが適切で速くなります

Typed Racketのお勉強 (11)

6 Typed-Untyped Interaction

Typedじゃない普通のRacketの関数からTyped Racketの関数は普通に呼べます
Typed RacketからRacketの関数を呼ぶにはrequire/typedで型を指定してやります

#lang racket

(provide (struct-out pt)
         distance)

(struct pt (x y))

(define (distance p1 p2)
  (sqrt (+ (sqr (- (pt-x p2) (pt-x p1)))
           (sqr (- (pt-y p2) (pt-y p1))))))

ここで定義されたでdistanceをTyped Racketから呼ぶには以下のように書きます
(chap06-01-distance.rktは上のファイル名)

(require/typed "chap06-01-distance.rkt"
               [#:struct pt ([x : Real] [y : Real])]
               [distance (-> pt pt Real)])

実行

> (distance (pt 3 5) (pt 7 0))
- : Real
6.4031242374328485

自分の作ったファイルだけでなく標準ライブラリからも同様にしてrequire/typedできます

Typed RacketからRacketの関数を呼ぶ場合、Contractを用いて型のチェックが
行われるため、場合によってはオーバーヘッドが発生するので注意、だそうです