utils: Type eval-with and eval1-with.

This commit is contained in:
Sergiu Ivanov 2022-01-16 23:10:08 +01:00
parent 906d339508
commit 28fdc23324
2 changed files with 42 additions and 42 deletions

View File

@ -1,6 +1,8 @@
#lang scribble/manual #lang scribble/manual
@(require scribble/example racket/sandbox @(require scribble/example racket/sandbox
(for-label racket graph "../utils.rkt")) (for-label racket graph (submod "../utils.rkt" typed)
(only-in typed/racket/base
Any AnyValues)))
@title[#:tag "utils"]{dds/utils: Various Utilities} @title[#:tag "utils"]{dds/utils: Various Utilities}
@ -19,7 +21,7 @@ module, so you cannot yet use the types directly.
(parameterize ([sandbox-output 'string] (parameterize ([sandbox-output 'string]
[sandbox-error-output 'string] [sandbox-error-output 'string]
[sandbox-memory-limit 50]) [sandbox-memory-limit 50])
(make-evaluator 'racket/base #:requires '("utils.rkt")))) (make-evaluator 'typed/racket/base #:requires '((submod "utils.rkt" typed)))))
@section{Base types} @section{Base types}
@ -42,7 +44,7 @@ This section defines some utilities to streamline the usage of hash tables
mapping symbols to values. The goal is essentially to avoid having to write mapping symbols to values. The goal is essentially to avoid having to write
explicit @racket[hash-ref] calls. explicit @racket[hash-ref] calls.
@defproc[(eval-with [ht variable-mapping?] [expr any/c]) any]{ @defproc[(eval-with [ht (VariableMapping Any)] [expr Any]) AnyValues]{
Temporarily injects the mappings from the given hash table as bindings in Temporarily injects the mappings from the given hash table as bindings in
a namespace including @racket[racket/base] and then evaluates the expression. a namespace including @racket[racket/base] and then evaluates the expression.
@ -63,6 +65,16 @@ missing identifier:
(eval-with ht '(+ b z a 1))) (eval-with ht '(+ b z a 1)))
)]} )]}
@defproc[(eval1-with [ht (VariableMapping Any)] [expr Any]) Any]{
Like @racket[eval-with], but returns only the first value computed by
@racket[expr].
@examples[#:eval utils-evaluator
(let ([ht (hash 'a 1 'b 1)])
(eval1-with ht '(+ b a 1)))
]}
@section{Analysis of quoted expressions} @section{Analysis of quoted expressions}
@section{Org-mode interoperability} @section{Org-mode interoperability}

View File

@ -11,21 +11,43 @@
;;; Typed section. ;;; Typed section.
(module typed typed/racket (module typed typed/racket
(require typed/graph (require typed/graph typed/rackunit
(for-syntax syntax/parse racket/list)) (for-syntax syntax/parse racket/list))
(provide (all-defined-out))
(provide eval-with eval1-with)
(define-type Variable Symbol) (define-type Variable Symbol)
(define-type (VariableMapping A) (Immutable-HashTable Variable A))) (define-type (VariableMapping A) (Immutable-HashTable Variable A))
(: eval-with (-> (VariableMapping Any) Any AnyValues))
(define (eval-with ht expr)
(parameterize ([current-namespace (make-base-namespace)])
(for ([(x val) (in-hash ht)]) (namespace-set-variable-value! x val))
(eval expr)))
(: eval1-with (-> (VariableMapping Any) Any Any))
(define (eval1-with ht expr)
(call-with-values (λ () (eval-with ht expr))
(λ args (car args))))
(module+ test
(test-case "eval-with"
(check-equal? (eval1-with (hash 'a 1 'b 2) '(+ a b 1))
4)
(define ht : (VariableMapping Integer) (hash 'a 1 'b 2))
(define expr : Any '(+ a b 1))
(check-equal? (eval1-with ht expr)
4))))
(require 'typed) (require 'typed)
(provide eval-with eval1-with)
;;; Untyped section. ;;; Untyped section.
(provide (provide
;; Functions ;; Functions
(contract-out [eval-with (-> variable-mapping? any/c any)] (contract-out [extract-symbols (-> any/c list?)]
[extract-symbols (-> any/c list?)]
[any->string (-> any/c string?)] [any->string (-> any/c string?)]
[stringify-variable-mapping (-> variable-mapping? string-variable-mapping?)] [stringify-variable-mapping (-> variable-mapping? string-variable-mapping?)]
[string->any (-> string? any/c)] [string->any (-> string? any/c)]
@ -171,40 +193,6 @@
(string->symbol (substring x-str 1)) (string->symbol (substring x-str 1))
x)))) x))))
;;; Temporarily injects the mappings from the given hash table as
;;; bindings in a namespace including racket/base and then evaluates
;;; the expression.
;;;
;;; > (let ([ht #hash((a . 1) (b . 1))])
;;; (eval-with ht '(+ b a 1)))
;;; 3
;;;
;;; The local bindings from the current lexical scope are not
;;; conserved. Therefore, the following outputs an error about a
;;; missing identifier:
;;;
;;; > (let ([ht #hash((a . 1) (b . 1))]
;;; [z 1])
;;; (eval-with ht '(+ b z a 1)))
;;;
(define (eval-with ht expr)
(parameterize ([current-namespace (make-base-namespace)])
(for ([(x val) ht]) (namespace-set-variable-value! x val))
(eval expr)))
(module+ test
(test-case "eval-with"
(check-equal? (let ([ht #hash((a . 1) (b . 1))])
(eval-with ht '(+ b a 1)))
3)))
;;; Same as eval-with, but returns only the first value produced by
;;; the evaluated expression.
(define (eval-with1 ht expr)
(let ([vals (call-with-values (λ () (eval-with ht expr))
(λ vals vals))])
(car vals)))
;;; ============================== ;;; ==============================
;;; Analysis of quoted expressions ;;; Analysis of quoted expressions