This document lists core standard-library functions and the optional default .NET runtime extern catalog. Core functions are loaded automatically by FScript.Language. Runtime functions require host registration through FScript.Runtime.Registry.all; the CLI enables them by default. Env is a CLI/REPL-injected value, not an always-injected language value.
- Core:
Env.setExitCode,List,Option,Map,Int,Float,Bool,String. - Default .NET runtime:
Console,Task,Fs,Json,Regex,Xml,Hash,Guid.
ignore : 'a -> unitis an always-available core function.Env : Environmentis injected by CLI/REPL hosts.
Console.writeLine : string -> unitConsole.readLine : unit -> string option
type Environment = { ScriptName: string option; Arguments: string list }type FsKind = File of string | Directory of string | Missinglet Env : Environment- Injected by the CLI and REPL hosts.
Env.ScriptNameisSome "<path>"for file execution andNonefor stdin/REPL execution.Env.Argumentscontains script arguments passed after--.
- Functions are curried.
- Core functions remain available when default runtime externs are disabled.
- Top-level script bindings cannot collide with reserved stdlib names.
ignoreis a built-in language function.- Console I/O is host-provided through runtime externs.
- Task concurrency helpers are host-provided through the default runtime extern registry:
Task.spawn : (unit -> 'a) -> 'a taskTask.await : 'a task -> 'a
- Indexer:
values[index] : 'a option - Signature:
'a list -> int -> 'a option - Description:
- zero-based optional index access
- negative or out-of-range indices return
None
- Indexer:
values[key] : 'v option - Signature:
'v map['key] -> 'key -> 'v option - Description:
- optional lookup by a key matching the map's key type
- missing keys return
None - map keys may be
string,int,bool, or a union whose cases all have no payload
- Constructors:
Some : 'a -> 'a optionNone : 'a option
- Module functions:
Task.spawn : (unit -> 'a) -> 'a taskTask.await : 'a task -> 'a
- Description:
Task.spawnschedules a thunk for concurrent execution and returns an opaque task handle immediatelyTask.awaitwaits for completion and returns the result value- task failures are fatal runtime errors
- execution joins all tasks before returning and collects foreground and background failures
- hosts may disable
Task.*by omitting those externs
- Field access:
record.Field - Signature:
{ Field: 'a; ... } -> 'a
- Access model:
- tuples are consumed via destructuring and pattern matching
- tuples do not have a native indexer
List.empty : 'a listList.map : ('a -> 'b) -> 'a list -> 'b listList.iter : ('a -> unit) -> 'a list -> unitList.choose : ('a -> 'b option) -> 'a list -> 'b listList.collect : ('a -> 'b list) -> 'a list -> 'b listList.exists : ('a -> bool) -> 'a list -> boolList.contains : 'a -> 'a list -> boolList.rev : 'a list -> 'a listList.distinct : 'a list -> 'a listList.fold : ('state -> 'a -> 'state) -> 'state -> 'a list -> 'stateList.filter : ('a -> bool) -> 'a list -> 'a listList.length : 'a list -> intList.tryFind : ('a -> bool) -> 'a list -> 'a optionList.tryGet : ('a -> bool) -> 'a list -> int optionList.tryItem : int -> 'a list -> 'a optionList.tryHead : 'a list -> 'a optionList.tail : 'a list -> 'a listList.append : 'a list -> 'a list -> 'a list
Option.defaultValue : 'a -> 'a option -> 'aOption.defaultWith : (unit -> 'a) -> 'a option -> 'aOption.isNone : 'a option -> boolOption.isSome : 'a option -> boolOption.map : ('a -> 'b) -> 'a option -> 'b option
Task.spawn : (unit -> 'a) -> 'a taskTask.await : 'a task -> 'a
Map.empty : 'v map['key](alias of{}).Map.tryGet : 'key -> 'v map['key] -> 'v optionMap.containsKey : 'key -> 'v map['key] -> boolMap.add : 'key -> 'v -> 'v map['key] -> 'v map['key]Map.ofList : ('key * 'v) list -> 'v map['key]Map.fold : ('state -> 'key -> 'v -> 'state) -> 'state -> 'v map['key] -> 'stateMap.count : 'v map['key] -> intMap.filter : ('key -> 'v -> bool) -> 'v map['key] -> 'v map['key]Map.choose : ('key -> 'v -> 'u option) -> 'v map['key] -> 'u map['key]Map.map : ('v -> 'u) -> 'v map['key] -> 'u map['key]Map.iter : ('key -> 'v -> unit) -> 'v map['key] -> unitMap.remove : 'key -> 'v map['key] -> 'v map['key]
Map keys may be string, int, bool, or a union whose cases all have no payload.
Int.tryParse : string -> int optionInt.toString : int -> string
Float.tryParse : string -> float optionFloat.toString : float -> string
Bool.tryParse : string -> bool optionBool.toString : bool -> string
String.replace : string -> string -> string -> string- argument order:
oldValue -> newValue -> source - Replaces all non-overlapping occurrences using ordinal, case-sensitive matching. An empty
oldValuereturnssourceunchanged; an emptynewValueremoves matches. This operation always returns a string.
- argument order:
String.indexOf : string -> string -> int option- argument order:
value -> source
- argument order:
String.toLower : string -> stringString.toUpper : string -> stringString.substring : int -> int -> string -> string option- argument order:
start -> length -> source
- argument order:
String.concat : string -> string list -> stringString.split : string -> string -> string list- argument order:
separator -> source
- argument order:
String.endsWith : string -> string -> bool- argument order:
suffix -> source
- argument order:
List.tail []raises an evaluation error.List.containscompares scalar values only; for composite data useList.exists (fun item -> item = expected).List.distinctpreserves first occurrence order and compares composite data recursively, including visible host-managed fields.Map.ofListkeeps the final value for a duplicate key; map traversal follows key order.String.splitpreserves empty entries; text searching is ordinal and case-sensitive.
The following functions require runtime registration. See external functions for argument order, filesystem policy, serialization constraints, and provider behavior.
Console.readLine : unit -> string optionConsole.writeLine : string -> unitFs.combinePath : string -> string -> stringFs.createDirectory : string -> boolFs.enumerateFiles : string -> string -> string list optionFs.exists : string -> boolFs.extension : string -> string optionFs.fileNameWithoutExtension : string -> stringFs.glob : string -> string list optionFs.kind : string -> FsKindFs.parentDirectory : string -> string optionFs.readText : string -> string optionFs.writeText : string -> string -> boolGuid.new : 'a -> string optionHash.md5 : string -> string optionJson.deserialize : type -> string -> 'a optionJson.serialize : 'a -> string optionRegex.matchGroups : string -> string -> string list optionTask.await : 'a task -> 'aTask.spawn : (unit -> 'a) -> 'a taskXml.queryValues : string -> string -> string list option
Json.deserialize selects a decoder from a runtime token; its generic scheme does not statically associate the token and output. Guid.new ignores its argument; scripts conventionally pass (). Filesystem and serialization options represent supported absence/conversion failure, not a universal exception boundary.
let xs = List.map (fun x -> x + 1) [1;2;3]
let found = List.tryFind (fun x -> x > 2) xs
let maybeSecond = List.tryItem 1 xs
let maybePort = Some 8080
let port = maybePort |> Option.defaultValue 80
let m = { ["a"] = 1; ["b"] = 2 }
let hasA = Map.containsKey "a" m
let one = m["a"] |> Option.defaultValue 0
let first = xs[0] |> Option.defaultValue 0
match Env.Arguments with
| scriptPath :: _ -> Console.writeLine scriptPath
| [] -> Console.writeLine "no args"Env.setExitCode : int -> unit is an always-available core operation, including in embedding and JavaScript. It coexists with host-provided Env.ScriptName and Env.Arguments without adding a field to the Environment record. The qualified operation is reserved even when an Env value is in scope.
On .NET and compiled targets, the code must be in the portable shell range 0..255; other values fail with an evaluation error. It selects the eventual shell status and returns unit normally. It never calls process exit, cancels tasks, or changes a host process's exit status during embedded evaluation. The default is 0, repeated calls use the last completed write, and unhandled execution failures still produce failure rather than a selected success code.
This operation is effectful and is not Pure. Its writes survive pruning and common-subexpression elimination. Writes from tasks share the execution status and are synchronized, but their order is scheduling-dependent. For deterministic status, await tasks and set it afterward in the main flow. Existing task lifetime and failure rules are preserved.
Env.setExitCode 7
42 // still evaluated; shell status is 7Result printing is independent of this status. --no-result suppresses automatic display in the CLI and can be baked into compiled applications.
Fable/JavaScript deliberately treats this operation as a no-op (including shell-range validation). Arguments still evaluate normally, returned values remain unchanged, and the website displays the returned value as before.
The following functions extend the standard library. All core additions are reserved names, available without host externs, and implemented by the evaluator, artifact interpreter, both native backends, and JavaScript engine. Encoding/SHA-256 remain separately registered .NET runtime externs; native outputs include equivalent BCL-only implementations. Existing IO capabilities are unchanged. The sandbox grants no additional filesystem, network, process, environment, clock, or random capability.
The website module references are the detailed behavioral contracts, including examples and failure behavior:
Int.abs : int -> intInt.sign : int -> intInt.min : int -> int -> intInt.max : int -> int -> intInt.clamp : int -> int -> int -> intFloat.abs : float -> floatFloat.sign : float -> intFloat.min : float -> float -> floatFloat.max : float -> float -> floatFloat.clamp : float -> float -> float -> floatFloat.floor : float -> floatFloat.ceil : float -> floatFloat.round : float -> floatFloat.truncate : float -> floatFloat.sqrt : float -> floatFloat.log : float -> floatFloat.log10 : float -> floatFloat.exp : float -> floatFloat.sin : float -> floatFloat.cos : float -> floatFloat.tan : float -> floatFloat.asin : float -> floatFloat.acos : float -> floatFloat.atan : float -> floatFloat.pow : float -> float -> floatFloat.atan2 : float -> float -> floatFloat.isNaN : float -> boolFloat.isInfinity : float -> boolFloat.isFinite : float -> boolFloat.pi : floatInt.toFloat : int -> floatFloat.tryToInt : float -> int optionString.length : string -> intString.isEmpty : string -> boolString.isWhiteSpace : string -> boolString.trim : string -> stringString.trimStart : string -> stringString.trimEnd : string -> stringString.splitLines : string -> string listString.startsWith : string -> string -> boolString.contains : string -> string -> boolString.padLeft : int -> string -> stringString.padRight : int -> string -> stringString.repeat : int -> string -> stringList.isEmpty : 'a list -> boolList.forall : ('a -> bool) -> 'a list -> boolList.mapi : (int -> 'a -> 'b) -> 'a list -> 'b listList.indexed : 'a list -> ((int * 'a)) listList.init : int -> (int -> 'a) -> 'a listList.take : int -> 'a list -> 'a listList.skip : int -> 'a list -> 'a listList.takeWhile : ('a -> bool) -> 'a list -> 'a listList.skipWhile : ('a -> bool) -> 'a list -> 'a listList.partition : ('a -> bool) -> 'a list -> ('a list * 'a list)List.zip : 'a list -> 'b list -> (('a * 'b)) listList.unzip : (('a * 'b)) list -> ('a list * 'b list)List.chunkBySize : int -> 'a list -> 'a list listList.scan : ('d -> 'a -> 'd) -> 'd -> 'a list -> 'd listList.sortWith : ('a -> 'a -> int) -> 'a list -> 'a listList.sortBy : ('a -> 'c) -> 'a list -> 'a listList.distinctBy : ('a -> 'c) -> 'a list -> 'a listList.groupBy : ('a -> 'c) -> 'a list -> (('c * 'a list)) listList.countBy : ('a -> 'c) -> 'a list -> (('c * int)) listMap.keys : 'a map['c] -> 'c listMap.values : 'a map['c] -> 'a listMap.toList : 'a map['c] -> (('c * 'a)) listMap.exists : ('c -> 'a -> bool) -> 'a map['c] -> boolMap.forall : ('c -> 'a -> bool) -> 'a map['c] -> boolMap.update : 'c -> ('a option -> 'a option) -> 'a map['c] -> 'a map['c]Map.mergeWith : ('c -> 'a -> 'a -> 'a) -> 'a map['c] -> 'a map['c] -> 'a map['c]Option.bind : ('a -> 'b option) -> 'a option -> 'b optionOption.flatten : 'a option option -> 'a optionOption.filter : ('a -> bool) -> 'a option -> 'a optionOption.orElse : 'a option -> 'a option -> 'a optionOption.orElseWith : (unit -> 'a option) -> 'a option -> 'a optionOption.map2 : ('a -> 'b -> 'd) -> 'a option -> 'b option -> 'd optionOption.toList : 'a option -> 'a listPath.normalize : string -> stringPath.isAbsolute : string -> boolPath.combine : string -> string -> stringPath.fileName : string -> stringPath.extension : string -> string optionPath.fileNameWithoutExtension : string -> stringPath.parent : string -> string optionPath.relative : string -> string -> string optionGlob.isMatch : string -> string -> boolGlob.filter : string -> string list -> string listSemVer.tryParse : string -> ({ Build: string; Major: string; Minor: string; Patch: string; PreRelease: string }) optionSemVer.format : { Build: string; Major: string; Minor: string; Patch: string; PreRelease: string } -> stringSemVer.compare : string -> string -> int optionEncoding.utf8Encode : string -> int list optionEncoding.utf8Decode : int list -> string optionEncoding.base64Encode : int list -> string optionEncoding.base64Decode : string -> int list optionEncoding.hexEncode : int list -> string optionEncoding.hexDecode : string -> int list optionEncoding.uriEncode : string -> string optionEncoding.uriDecode : string -> string optionHash.sha256 : string -> string optionHash.sha256Bytes : int list -> string option
Scalar string operations use UTF-16 indices and ordinal comparisons. Numeric conversions truncate explicitly and reject invalid ranges. Integer abs overflow, reversed clamp bounds, invalid sizes, unequal zip lengths, invalid glob grammar, and invalid SemVer formatting raise errors; parse/decode operations return options.
Higher-order helpers invoke callbacks through the evaluator trampoline. Sorts are stable bottom-up merge sorts with identical comparison order across .NET execution engines; sortBy computes projections once and compares scalar keys only. Group/distinct/count operations use structural equality and first occurrence order. Map operations preserve existing map key ordering. Callbacks retain their effects and failures; compiler purity remains conservative for partial or higher-order additions.
Paths always use portable slash-only lexical rules. Glob patterns never enumerate files. SemVer follows 2.0.0 precedence with unbounded decimal string components. UTF-8 is strict, Base64 uses the standard alphabet, hex outputs lowercase, URI decoding preserves plus signs, and SHA-256 hashes supplied bytes or strict UTF-8 text.
String.compare : string -> string -> int returns normalized ordinal ordering. Native ordered maps also use ordinal string ordering, matching evaluator maps independently of the current culture. Whitespace helpers use an explicit Unicode White_Space set shared by all engines rather than runtime-specific trim defaults.
The full optional runtime Task API is specified in the Task reference. Additions:
Task.delay : int -> unit taskTask.fromResult : 'a -> 'a taskTask.continueWith : ('a -> 'b) -> 'a task -> 'b taskTask.whenAll : ('a list -> 'b) -> 'a task list -> 'b taskTask.whenAny : ('a -> 'b) -> 'a task list -> 'b taskTask.awaitAll : 'a task list -> 'a list
Delays use timer waits, accepting only 0..2147483647 milliseconds. Completed-value tasks are completed immediately and preserve distinct task handles. Continuation callbacks are scheduled asynchronously, run once on successful prerequisites, receive ordinary values, and preserve nested task results without automatic flattening. All operations snapshot input list order. WhenAll/awaitAll preserve input order; empty all invokes the callback with [] and empty awaitAll returns []. Empty whenAny raises an error. Unit-valued candidates are ordinary homogeneous task lists. Different result types must first be mapped into an explicit user union; the type checker rejects heterogeneous task lists.
WhenAny registers the race at invocation, consumes only its selected task, and does not cancel losers. Already-completed inputs select the first completed list entry; other ties are scheduling-dependent. At top-level evaluator execution, evaluator exported-function calls, and generated Run boundaries, the runtime repeatedly joins all tracked tasks, including tasks created by other tasks and unobserved nested results, until every worker completes. Explicit observation is optional. Background failures do not interrupt independent siblings; failed prerequisites still prevent dependent callbacks. All fatal foreground/background errors are collected after joining. Propagated instances of the same error are reported once, while independent errors with identical messages remain distinct. The evaluator reports multiple failures in one EvalException; generated .NET code uses AggregateException. Single failures preserve their ordinary exception form. Separately invoked native exports have host-owned CLR task lifetimes. A worker or host extern that never completes prevents the boundary from returning; resource limits remain host-owned.
The canonical evaluator/SDK task functions remain optional runtime registrations. Fable task execution and unadapted standalone LIR task calls fail explicitly; compiler catalogs and artifacts preserve the signatures and arities. Tasks are observable scheduling capabilities and receive no automatic compiler purity guarantee.
Task continuation argument order is callback first and task/task list last. All three combinators support pipeline application and reusable partial application, e.g. let increment = Task.continueWith (fun value -> value + 1) followed by Task.fromResult 41 |> increment. Parameter metadata, evaluator/native/SDK dispatch, and static task-sharing analysis use this same order.