#lang scribble/manual @(require scribble/example racket/sandbox (for-label typed/racket/base "../functions.rkt" dds/utils typed/racket/unsafe)) @title[#:tag "functions"]{dds/functions: Formal Functions} @defmodule[dds/functions] This modules provides some definitions for working with functions: tabulating, (re)constructing from tables, generating random functions, etc. Some definitions of particular kinds of functions are also provided (threshold Boolean functions, etc.). @(define functions-evaluator (parameterize ([sandbox-output 'string] [sandbox-error-output 'string] [sandbox-memory-limit 50]) (make-evaluator 'typed/racket #:requires '((submod "functions.rkt" typed))))) @section{Tabulating functions} @defproc[(tabulate [func (-> a ... b)] [doms (List (Listof a) ... a)]) (Listof (Listof (U Any b)))]{ Given a function @racket[func] and a list of domains @racket[doms] for each of its arguments, in order, produces a list of lists giving the values of arguments and the value of the functions for these inputs. @examples[#:eval functions-evaluator (tabulate (λ (x y) (and x y)) '((#f #t) (#f #t))) ]} @defproc[(tabulate/strict [func (-> a ... b)] [doms (List (Listof a) ... a)]) (Listof (List (List a ...) (Listof b)))]{ Like @racket[tabulate], but the types of the arguments of @racket[func] explicitly appear in the return type. As of 2022-03-06, I am not able to write the type of a list first containing elements of types @racket[a ...], followed by an element of type @racket[b]. This is why this function returns a list of lists, each containing first a list of inputs, and then the output of @racket[func]. @examples[#:eval functions-evaluator (tabulate/strict (λ (x y) (and x y)) '((#f #t) (#f #t))) ]} @defproc[(tabulate/untyped [funcs procedure?] [doms (listof list?)]) (listof list?)]{ A version of @racket[tabulate] without type checking. As of 2022-03-06, Typed Racket cannot generate contracts for polymorphic variable-arity functions. This means that @racket[tabulate] cannot be used directly in untyped code and should be replaced by @racket[tabulate/untyped], which is simply an @racket[unsafe-provide] of @racket[tabulate]. @examples[#:eval functions-evaluator (tabulate/untyped (λ (x y) (and x y)) '((#f #t) (#f #t))) ] The contracts in the documentation entry are provided for explanatory purposes and are not actually enforced. Some contracts on the functions @racket[tabulate] uses internally are still checked. For example, trying to tabulate a function of wrong arity will still raise an error. @examples[#:eval functions-evaluator (module tabulate/untyped-test racket/base (require "functions.rkt") (tabulate/untyped (λ (x y z) (and x y z)) '((#f #t) (#f #t)))) (eval:error (require 'tabulate/untyped-test)) ]} @defproc[(tabulate* [funcs (Listof (-> a ... b))] [doms (List (Listof a) ... a)]) (Listof (Listof (U Any b)))]{ Like @racket[tabulate], but @racket[funcs] is a list of functions taking the same arguments over the same domains. @examples[#:eval functions-evaluator (tabulate* (list (λ (x y) (and x y)) (λ (x y) (or x y))) '((#f #t) (#f #t))) ]} @defproc[(tabulate*/strict [funcs (Listof (-> a ... b))] [doms (List (Listof a) ... a)]) (Listof (List (List a ...) (Listof b)))]{ Like @racket[tabulate*], but the types of the arguments of the functions explicitly appear in the return type. As of 2022-03-06, I am not able to write the type of a list first containing elements of types @racket[a ...], followed by a list of elements of type @racket[b]. This is why this function returns a list of lists, each containing first a list of inputs, and then the list of outputs of @racket[funcs]. @examples[#:eval functions-evaluator (tabulate*/strict (list (λ (x y) (and x y)) (λ (x y) (or x y))) '((#f #t) (#f #t))) ] The result of @racket[tabulate*] can be obtained by applying @racket[append-lists]: @examples[#:eval functions-evaluator (require (only-in "utils.rkt" append-lists)) (append-lists (tabulate*/strict (list (λ (x y) (and x y)) (λ (x y) (or x y))) '((#f #t) (#f #t)))) ]} @defproc[(tabulate*/untyped [funcs (listof procedure?)] [doms (listof list?)]) (listof list?)]{ A version of @racket[tabulate*] without type checking. As of 2022-03-06, Typed Racket cannot generate contracts for polymorphic variable-arity functions. This means that @racket[tabulate*] cannot be used directly in untyped code and should be replaced by @racket[tabulate*/untyped], which is simply an @racket[unsafe-provide] of @racket[tabulate*]. @examples[#:eval functions-evaluator (tabulate*/untyped (list (λ (x y) (and x y)) (λ (x y) (or x y))) '((#f #t) (#f #t))) ] The contracts in the documentation entry are provided for explanatory purposes and are not actually enforced. Some contracts on the functions @racket[tabulate*] uses internally are still checked. For example, trying to tabulate a function of wrong arity will still raise an error. @examples[#:eval functions-evaluator (module untyped-test racket/base (require "functions.rkt") (tabulate*/untyped (list (λ (x y z) (and x y z))) '((#f #t) (#f #t)))) (eval:error (require 'untyped-test)) ]} @section{Constructing functions} @section{Random functions} @section{Threshold Boolean functions}