Repository F# setup
open Reified
open Reified.Refinements
open Reified.ResultField Blocks and Plain Functions
The inner field block is syntax for transforming one Schema<_> value. It prevents configuration for adjacent fields
from joining into one pipeline.
Both forms below use a ContactEmail type and a validateCompanyEmail function shaped like the ones
Refined Schemas builds section by section, kept minimal here (one constraint, not
the full presence-plus-length-plus-format version that page settles on) since this page's subject is the field
block, not the refinement. Refinement.define pairs a constraint with the wrap/unwrap functions that make it a
type, covered there in detail:
open Reified
open Reified.Refinements
type ContactEmail =
private
| ContactEmail of string
module ContactEmail =
let value (ContactEmail value) = value
let refinement =
Refinement.define Constraint.email ContactEmail value
let validateCompanyEmail (email: ContactEmail) : Result<unit, SchemaError> =
if (ContactEmail.value email).EndsWith("@example.com") then Ok ()
else Error (SchemaError.Custom("company-email", Some "Company email must end with @example.com."))
ReifiedRefinementsFsLiveDocsGeneratedPage13_76B7E1D94D35.ContactEmailContactEmailstringAn abbreviation for the CLI type . Basic Types
FsLiveDocsGeneratedPage13_76B7E1D94D35.ContactEmailModulevalue: ContactEmail -> string_arg1: ContactEmailvalue: stringrefinement: Refinement<string,ContactEmail>Reified.Refinements.RefinementCreates and applies reusable refinement definitions.
define: Constraint<'underlying> -> ('underlying -> 'refined) -> ('refined -> 'underlying) -> Refinement<'underlying,'refined>Defines a refinement from one constraint, a constructor, and the reverse projection. Compose several rules with Constraint.all before defining, and reach for Constraint.custom when the rule is an arbitrary predicate. Both produce an ordinary constraint, so there is no separate plural or check-taking constructor. type RetryCount = RetryCount of int let retryCount = Refinement.define (Constraint.between 0 10) RetryCount (fun (RetryCount value) -> value)
Reified.ConstraintModuleCreates, executes, composes, and inspects constraints.
email: Constraint<string>Requires text to match Reified's pragmatic email shape, ^[^@]+@[^@]+$. let contact : Constraint<string> = Constraint.email
validateCompanyEmail: ContactEmail -> Result<unit,SchemaError>email: ContactEmailMicrosoft.FSharp.Core.FSharpResult`2Helper type for error handling without exceptions. Choices and Results
unitThe type 'unit', which has only one value "()". This value is special and always uses the representation 'null'. Basic Types
Reified.SchemaErrorSchema input, checking, and contextual rule failures attached to diagnostics paths. The parse/check axis is the organising split. Parsing cases mean the input could not be read as the declared type at all; Violation means it was read and then failed its constraint. Constraint failures are never lowered into a parse-shaped case, because a lowering that discards the atom forces consumers back to reconstructing constraint identity from strings.
EndsWith: string -> boolOkRepresents an OK or a Successful result. The code succeeded with a value of 'T.
ErrorRepresents an Error or a Failure. The code failed with a value of 'TError representing what went wrong.
CustomA Schema-owned intrinsic check failed.
SomeThe representation of "Value of type 'T" The input value. An option representing the value.
field _.Email {
withSchema Schema.text
refine ContactEmail.refinement
validate validateCompanyEmail
}Its schema transformation is:
Schema.text
|> Schema.refine ContactEmail.refinement
|> Schema.validate validateCompanyEmail
Reified.SchemaConstruction, composition, parsing, and checking for universal schemas.
text: Schema<string>Describes text input.
(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
refine: Refinement<'raw,'value> -> Schema<'raw> -> Schema<'value>Maps a raw schema through a reusable bidirectional refinement. The smart constructor runs during parsing. Inspection supplies the raw representation during checking and encoding.
FsLiveDocsGeneratedPage13_76B7E1D94D35.ContactEmailModulerefinement: Refinement<string,ContactEmail>validate: ('value -> Result<unit,SchemaError>) -> Schema<'value> -> Schema<'value>Adds executable value validation to a schema. The validation runs during parsing and when checking an existing value. It remains executable behavior and is not emitted as portable constraint metadata.
validateCompanyEmail: ContactEmail -> Result<unit,SchemaError>The outer declaration then attaches that Schema<ContactEmail> to the "email" field and its getter.
withSchema
withSchema replaces canonical type resolution for this field:
field _.Children {
withSchema (Schema.listWith childSchema)
}There is no separate fieldWith declaration. Explicit schema selection is always an operation inside the field.
Canonical resolution for generated contract types
A type resolves canonically when it exposes static member Schema: T -> Schema<T>. Reified supplies that member for
its built-in types, and reified schemagen emits it for every record it owns (the types declared in a .contract
file). A field whose type is such a contract, directly, or wrapped in list, option, or Map, therefore needs
no withSchema:
field _.Origin // Origin: Geo - Geo is a generated contract type
field _.Waypoints // Waypoints: Geo list
field _.Destination // Destination: Geo optionThe augmentation is intrinsic to the generated file, so it resolves from any assembly with no open. Types carried
by [<DeriveSchema>] on hand-written records are the exception: schemagen cannot add an intrinsic member to a type
it does not declare, so a field of such a type still selects its schema with withSchema TheType.schema.
constrain and constraints
Portable constraints can be inspected by JSON Schema, documentation, and UI interpreters. constraints takes a
list for several at once; constrain takes one:
field _.Name {
constraints [ present; maxLength 80 ]
}The plain function is Schema.constrain:
Schema.text
|> Schema.constrain Constraint.present
|> Schema.constrain (Constraint.maxLength 80)
Reified.SchemaConstruction, composition, parsing, and checking for universal schemas.
text: Schema<string>Describes text input.
(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
constrain: Constraint<'a> -> Schema<'a> -> Schema<'a>Requires a schema's values to satisfy a constraint. The same Constraint value serves direct checking, refinement, and Schema. For a value schema the constraint runs at that layer; for a model schema it runs after successful field admission and construction. Schema.text |> Schema.constrain (Constraint.lengthBetween 2 40)
Reified.ConstraintModuleCreates, executes, composes, and inspects constraints.
present: Constraint<^value>Requires a value to be inhabited according to its shape. Whitespace-only text is blank, as are null text, a null or empty collection or map, None, ValueNone, and an empty Nullable. Blankness means .NET's whitespace set plus U+FEFF, which is what lets the rule be exported; see nonBlankPattern. The shape is selected from the return type, so a reusable binding needs its annotation: let requiredName : Constraint<string> = Constraint.present. Applied where the type is already known — inside an annotated rule, or to a schema — no annotation is needed. let requiredName : Constraint<string> = Constraint.present
maxLength: int -> Constraint<^value>Requires text or a collection to have at most the supplied size. let summary : Constraint<string> = Constraint.maxLength 280
refine
The plain function receives a descriptor explicitly:
let contactEmailSchema =
Schema.text
|> Schema.refine ContactEmail.refinement
contactEmailSchema: Schema<ContactEmail>Reified.SchemaConstruction, composition, parsing, and checking for universal schemas.
text: Schema<string>Describes text input.
(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
refine: Refinement<'raw,'value> -> Schema<'raw> -> Schema<'value>Maps a raw schema through a reusable bidirectional refinement. The smart constructor runs during parsing. Inspection supplies the raw representation during checking and encoding.
FsLiveDocsGeneratedPage13_76B7E1D94D35.ContactEmailModulerefinement: Refinement<string,ContactEmail>Inside the field block, either supply the same value or use the destination type's canonical contribution:
field _.Email {
withSchema Schema.text
refine ContactEmail.refinement
}type ContactEmail with
static member Refinement(_: string, _: ContactEmail) = ContactEmail.refinement
FsLiveDocsGeneratedPage13_76B7E1D94D35.ContactEmailRefinement: string * ContactEmail -> Refinement<string,ContactEmail>stringAn abbreviation for the CLI type . Basic Types
FsLiveDocsGeneratedPage13_76B7E1D94D35.ContactEmailModulerefinement: Refinement<string,ContactEmail>field _.Email {
withSchema Schema.text
refine
}The bare form uses the current string schema and the ContactEmail getter type as its compile-time dispatch key.
validate
Executable validation preserves the current type:
let companyEmailSchema =
contactEmailSchema
|> Schema.validate validateCompanyEmail
companyEmailSchema: Schema<ContactEmail>contactEmailSchema: Schema<ContactEmail>(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Reified.SchemaConstruction, composition, parsing, and checking for universal schemas.
validate: ('value -> Result<unit,SchemaError>) -> Schema<'value> -> Schema<'value>Adds executable value validation to a schema. The validation runs during parsing and when checking an existing value. It remains executable behavior and is not emitted as portable constraint metadata.
validateCompanyEmail: ContactEmail -> Result<unit,SchemaError>Inside the block:
field _.Email {
validate validateCompanyEmail
}Schema attaches the field path if the function fails. Arbitrary executable validation is not emitted as JSON Schema metadata; use a built-in constraint for facts other interpreters must read.