In my last post I showed a bare bones implementation of formlets. You may have noticed that formlets do a lot of stuff:
- Generating form element names
- Handling submitted values
- Building and rendering HTML
That's a lot of responsibilities for a single module. Even the type of a formlet reflects this, it's pretty complex:
type 'a Formlet = int -> (xml_item list * ((string * string) list -> 'a) * int)
And we haven't even looked at adding validation, which would complicate things further. Bottom line: there is no clear separation of concerns.
The good news are: we already have identified those concerns (the bulleted list above), and applicative functors are easily composable, so we can model each of those concerns as independent applicative functors, then compose them to yield formlets.
HTML building
As usual, we start by defining types: the same definition for XML trees:
type xml_item =
| Text of string
| Tag of string * (string*string) list * xml_item list
And the type of the applicative functor itself:
type 'a XmlWriter = xml_item list * 'a
A XML forest and something else. That 'something else' is what will enable the composition of this applicative with others.
Finally, the implementation. If you compare this with the implementation of formlets described in the previous post, function by function, you'll see that this is effectively a stripped down applicative that only deals with XML.
module XmlWriter =
let puree (v: 'a) : 'a XmlWriter = [],v
let (<*>) (f: ('a -> 'b) XmlWriter) (a: 'a XmlWriter) : 'b XmlWriter =
fst f @ fst a, (snd f) (snd a)
let lift f a = puree f <*> a
let lift2 f a b = puree f <*> a <*> b
let plug (f: xml_item list -> xml_item list) (a: 'a XmlWriter) : 'a XmlWriter =
f (fst a), snd a
let xml (e: xml_item list): unit XmlWriter = e,()
let text (s: string) : unit XmlWriter =
xml [Text s]
let tag (t: string) (attr: (string*string) list) (v: 'a XmlWriter) : 'a XmlWriter =
plug (fun x -> [Tag(t, attr, x)]) v
open System.Xml.Linq
let render (xml: xml_item list) : XDocument =
let (!!) t = XName.op_Implicit t
let xtext (s: string) = XText s :> XObject
let xattr (name, value) = XAttribute(!!name, value) :> XObject
let xattrs attr = List.map xattr attr
let xelem name attr children = XElement(!!name, attr @ children) :> XObject
let rec renderForest x =
let render' =
function
| Text t -> xtext t
| Tag(name, attr, children) -> xelem name (xattrs attr) (renderForest children)
List.map render' x
let root = xelem "div" [] (renderForest xml)
XDocument root
The only additional function here is plug, which maps the XML forest in a XmlWriter applicative. It's not of much use here and could be inlined, but it will be useful later to implement validation (in a future post).
Environment handling
The environment (or collector) applicative is one that fetches (collects) a value from the environment (usually Request.Form in ASP.NET). As such, its type is
type 'a Environ = (string*string) list -> 'a
The implementation:
module Environ =
let puree v = fun env -> v
let (<*>) (f: ('a -> 'b) Environ) (a: 'a Environ) : 'b Environ =
fun env ->
let g = f env
g(a(env))
let lift f a = puree f <*> a
let lookup (n: string) : string Environ =
fun env ->
match List.tryFind (fun (k,_) -> k = n) env with
| Some (_,v) -> v
| _ -> failwithf "Key %s not found in environment" n
Note the lookup function, it's an Environ constructor that implements the core functionality of "given this key and this environment, give me the corresponding value". It's pretty much a dictionary in applicative form.
We'll also add here a helper function to convert a NameValueCollection (like Request.Form) to an environment:
open System.Collections.Specialized
let fromNV (a: NameValueCollection) =
a.AllKeys
|> Seq.collect (fun k -> a.GetValues k |> Seq.map (fun v -> k,v))
|> Seq.toList
Name generation
We've seen how formlets automatically generate form element names. While the actual generation is provided by nextName, the counter used is carried over from application to application, since this is purely functional code, without state:
type 'a NameGen = int -> 'a * int
module NameGen =
let puree (v : 'a) : 'a NameGen =
fun gen -> v,gen
let (<*>) (f: ('a -> 'b) NameGen) (a: 'a NameGen) : 'b NameGen =
fun gen ->
let v,gen = f gen
let w,gen = a gen
v w, gen
let lift f a = puree f <*> a
let lift2 f a b = puree f <*> a <*> b
let nextName : string NameGen =
fun gen ->
"input_" + gen.ToString(), gen+1
let run (c: 'a NameGen) : 'a = fst (c 0)
Here's a simple example of name generation:
> open NameGen;;
> let names = puree (printfn "%s %s") <*> nextName <*> nextName;;
> run names;;
input_0 input_1
Composing applicatives
Applicative functors are easily composable, and the composition of any two applicatives is an applicative (math people say they're closed under composition). Interestingly, monads are not closed under composition, which as far as I understand is the reason for having monad transformers, but this doesn't seem to be a problem in F# since monads aren't as ubiquitous as in Haskell anyway.
Composing two applicatives is as simple as applying one applicative's pure to the other applicative's pure, and lifting <*>
. Again, since we can't abstract type constructors, we can't perform composition generically, but we can always do it ad-hoc.
type 'a EnvironXmlWriter = 'a Environ XmlWriter
Expanding the types, this means
type 'a EnvironXmlWriter = xml_item list * ((string * string) list -> 'a)
The implementation:
module EnvironXmlWriter =
let puree (v: 'a) : 'a Environ XmlWriter =
v |> Environ.puree |> XmlWriter.puree
let (<*>) (f: ('a -> 'b) Environ XmlWriter) (a: 'a Environ XmlWriter) : 'b Environ XmlWriter =
XmlWriter.lift2 Environ.(<*>) f a
let lift f a = puree f <*> a
We'll also add a refine function that lets us build the composition from the "wrapping" applicative (in our case XmlWriter). Building it from the nested applicative is as easy as applying XmlWriter.pure.
let refine (x: 'a XmlWriter) : 'a Environ XmlWriter =
XmlWriter.lift Environ.puree x
Example:
let input : string Environ XmlWriter =
let xml = [Tag("input",["name","firstname"],[])]
let lookup = Environ.lookup "firstname"
xml,lookup
This is almost a formlet. Just like a fully-fledged formlet, it has a XML part that can be rendered, and an associated collector. The only thing missing here is the automatic name generation applied to both the XML element and the collector.
Finally Formlets
All we have to do now is compose EnvironXmlWriter with NameGen to yield Formlets. Its type is:
type 'a Formlet = 'a EnvironXmlWriter NameGen
or
type 'a Formlet = 'a Environ XmlWriter NameGen
or if we expand each type:
type 'a Formlet = int -> (xml_item list * ((string * string) list -> 'a) * int)
which is exactly what we had in the last post. As you can see, factoring it to primitive applicatives has given us a clearer definition.
The implementation of formlets is almost trivial now:
module Formlet =
let puree v : _ Formlet = v |> EnvironXmlWriter.puree |> NameGen.puree
let (<*>) (f: ('a -> 'b) Formlet) (a: 'a Formlet) : 'b Formlet =
NameGen.lift2 EnvironXmlWriter.(<*>) f a
let lift f a : _ Formlet = puree f <*> a
let lift2 f a b : _ Formlet = puree f <*> a <*> b
let ( *>) f a : _ Formlet = lift2 (fun _ z -> z) f a
let ( <*) f a : _ Formlet = lift2 (fun z _ -> z) f a
let xml (x: xml_item list) : unit Formlet =
NameGen.puree (EnvironXmlWriter.refine (XmlWriter.xml x))
let text (s: string) : unit Formlet =
xml [Text s]
let tag (t: string) (attr: (string*string) list) (f: 'a Formlet) : 'a Formlet =
NameGen.lift (XmlWriter.tag t attr) f
let input : string Formlet =
let xml name = XmlWriter.tag "input" ["name",name]
let lookup name = XmlWriter.puree (Environ.lookup name)
let tag name = xml name (lookup name)
NameGen.lift tag NameGen.nextName
let br: unit Formlet = xml [Tag("br",[],[])]
let run (f: 'a Formlet) : 'a Environ =
NameGen.run f |> snd
open System.Xml.Linq
let render (f: _ Formlet) =
NameGen.run f |> fst |> XmlWriter.render
F# Web Snippets
Factoring formlets like this not only has the advantage of producing cleaner code, but also enables the reusability of each applicative functor and extending formlets more easily, as we'll see in a future post.
Full source code is here. This implementation is interchangeable with the one in my last post, the project includes both implementations so you can compare them side by side. Most of this code was taken almost verbatim from the original papers on formlets.
namespace Formlets
Multiple items
val int : 'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
type: int<'Measure>
implements: System.IComparable
implements: System.IConvertible
implements: System.IFormattable
implements: System.IComparable<int<'Measure>>
implements: System.IEquatable<int<'Measure>>
inherits: System.ValueType
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
type: int
implements: System.IComparable
implements: System.IFormattable
implements: System.IConvertible
implements: System.IComparable<int>
implements: System.IEquatable<int>
inherits: System.ValueType
val puree : 'a -> int -> 'a * int
Full name: Formlets.NameGen.puree
val v : 'a
type 'a NameGen = int -> 'a * int
Full name: Formlets.NameGen<_>
val gen : int
type: int
implements: System.IComparable
implements: System.IFormattable
implements: System.IConvertible
implements: System.IComparable<int>
implements: System.IEquatable<int>
inherits: System.ValueType
val f : ('a -> 'b) NameGen
val a : 'a NameGen
val v : ('a -> 'b)
val w : 'a
val lift : ('a -> 'b) -> 'a NameGen -> 'b NameGen
Full name: Formlets.NameGen.lift
val f : ('a -> 'b)
val lift2 : ('a -> 'b -> 'c) -> 'a NameGen -> 'b NameGen -> 'c NameGen
Full name: Formlets.NameGen.lift2
val f : ('a -> 'b -> 'c)
val b : 'b NameGen
val nextName : int -> string * int
Full name: Formlets.NameGen.nextName
Multiple items
val string : 'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
type: string
implements: System.IComparable
implements: System.ICloneable
implements: System.IConvertible
implements: System.IComparable<string>
implements: seq<char>
implements: System.Collections.IEnumerable
implements: System.IEquatable<string>
Multiple overloads
System.Object.ToString() : string
System.Int32.ToString(provider: System.IFormatProvider) : string
System.Int32.ToString(format: string) : string
System.Int32.ToString(format: string, provider: System.IFormatProvider) : string
val run : 'a NameGen -> 'a
Full name: Formlets.NameGen.run
val c : 'a NameGen
val fst : ('T1 * 'T2) -> 'T1
Full name: Microsoft.FSharp.Core.Operators.fst
type 'a Environ = (string * string) list -> 'a
Full name: Formlets.Environ<_>
type 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>
type: 'T list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<'T>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<'T>
implements: System.Collections.IEnumerable
val puree : 'a -> 'b -> 'a
Full name: Formlets.Environ.puree
val env : 'b
val f : ('a -> 'b) Environ
val a : 'a Environ
val env : (string * string) list
type: (string * string) list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<string * string>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<string * string>
implements: System.Collections.IEnumerable
val g : ('a -> 'b)
val lift : ('a -> 'b) -> 'a Environ -> 'b Environ
Full name: Formlets.Environ.lift
val lookup : string -> (string * string) list -> string
Full name: Formlets.Environ.lookup
val n : string
type: string
implements: System.IComparable
implements: System.ICloneable
implements: System.IConvertible
implements: System.IComparable<string>
implements: seq<char>
implements: System.Collections.IEnumerable
implements: System.IEquatable<string>
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of 'T * 'T list
with
interface System.Collections.IEnumerable
interface System.Collections.Generic.IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
end
Full name: Microsoft.FSharp.Collections.List<_>
type: List<'T>
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<'T>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<'T>
implements: System.Collections.IEnumerable
val tryFind : ('T -> bool) -> 'T list -> 'T option
Full name: Microsoft.FSharp.Collections.List.tryFind
val k : string
type: string
implements: System.IComparable
implements: System.ICloneable
implements: System.IConvertible
implements: System.IComparable<string>
implements: seq<char>
implements: System.Collections.IEnumerable
implements: System.IEquatable<string>
union case Option.Some: 'T -> Option<'T>
val v : string
type: string
implements: System.IComparable
implements: System.ICloneable
implements: System.IConvertible
implements: System.IComparable<string>
implements: seq<char>
implements: System.Collections.IEnumerable
implements: System.IEquatable<string>
val failwithf : Printf.StringFormat<'T,'Result> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.failwithf
namespace System
namespace System.Collections
namespace System.Collections.Specialized
val fromNV : NameValueCollection -> (string * string) list
Full name: Formlets.Environ.fromNV
val a : NameValueCollection
type: NameValueCollection
implements: System.Collections.ICollection
implements: System.Collections.IEnumerable
implements: System.Runtime.Serialization.ISerializable
implements: System.Runtime.Serialization.IDeserializationCallback
inherits: NameObjectCollectionBase
type NameValueCollection =
class
inherit System.Collections.Specialized.NameObjectCollectionBase
new : unit -> System.Collections.Specialized.NameValueCollection
new : System.Collections.Specialized.NameValueCollection -> System.Collections.Specialized.NameValueCollection
new : System.Collections.IHashCodeProvider * System.Collections.IComparer -> System.Collections.Specialized.NameValueCollection
new : int -> System.Collections.Specialized.NameValueCollection
new : System.Collections.IEqualityComparer -> System.Collections.Specialized.NameValueCollection
new : int * System.Collections.IEqualityComparer -> System.Collections.Specialized.NameValueCollection
new : int * System.Collections.Specialized.NameValueCollection -> System.Collections.Specialized.NameValueCollection
new : int * System.Collections.IHashCodeProvider * System.Collections.IComparer -> System.Collections.Specialized.NameValueCollection
member Add : System.Collections.Specialized.NameValueCollection -> unit
member Add : string * string -> unit
member AllKeys : string []
member Clear : unit -> unit
member CopyTo : System.Array * int -> unit
member Get : string -> string
member Get : int -> string
member GetKey : int -> string
member GetValues : string -> string []
member GetValues : int -> string []
member HasKeys : unit -> bool
member Item : string -> string with get, set
member Item : int -> string
member Remove : string -> unit
member Set : string * string -> unit
end
Full name: System.Collections.Specialized.NameValueCollection
type: NameValueCollection
implements: System.Collections.ICollection
implements: System.Collections.IEnumerable
implements: System.Runtime.Serialization.ISerializable
implements: System.Runtime.Serialization.IDeserializationCallback
inherits: NameObjectCollectionBase
property NameValueCollection.AllKeys: string []
module Seq
from Microsoft.FSharp.Collections
val collect : ('T -> #seq<'U>) -> seq<'T> -> seq<'U>
Full name: Microsoft.FSharp.Collections.Seq.collect
Multiple overloads
NameValueCollection.GetValues(index: int) : string []
NameValueCollection.GetValues(name: string) : string []
val map : ('T -> 'U) -> seq<'T> -> seq<'U>
Full name: Microsoft.FSharp.Collections.Seq.map
val toList : seq<'T> -> 'T list
Full name: Microsoft.FSharp.Collections.Seq.toList
type xml_item =
| Text of string
| Tag of string * (string * string) list * xml_item list
Full name: Formlets.xml_item
type: xml_item
implements: System.IEquatable<xml_item>
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<xml_item>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
union case xml_item.Text: string -> xml_item
union case xml_item.Tag: string * (string * string) list * xml_item list -> xml_item
type 'a XmlWriter = xml_item list * 'a
Full name: Formlets.XmlWriter<_>
val puree : 'a -> 'a XmlWriter
Full name: Formlets.XmlWriter.puree
val f : ('a -> 'b) XmlWriter
val a : 'a XmlWriter
val snd : ('T1 * 'T2) -> 'T2
Full name: Microsoft.FSharp.Core.Operators.snd
val lift : ('a -> 'b) -> xml_item list * 'a -> 'b XmlWriter
Full name: Formlets.XmlWriter.lift
val lift2 : ('a -> 'b -> 'c) -> xml_item list * 'a -> xml_item list * 'b -> 'c XmlWriter
Full name: Formlets.XmlWriter.lift2
val b : 'b XmlWriter
val plug : (xml_item list -> xml_item list) -> xml_item list * 'a -> 'a XmlWriter
Full name: Formlets.XmlWriter.plug
val f : (xml_item list -> xml_item list)
val xml : xml_item list -> unit XmlWriter
Full name: Formlets.XmlWriter.xml
val e : xml_item list
type: xml_item list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<xml_item>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<xml_item>
implements: System.Collections.IEnumerable
type unit = Unit
Full name: Microsoft.FSharp.Core.unit
type: unit
implements: System.IComparable
val text : string -> unit XmlWriter
Full name: Formlets.XmlWriter.text
val s : string
type: string
implements: System.IComparable
implements: System.ICloneable
implements: System.IConvertible
implements: System.IComparable<string>
implements: seq<char>
implements: System.Collections.IEnumerable
implements: System.IEquatable<string>
val tag : string -> (string * string) list -> xml_item list * 'a -> 'a XmlWriter
Full name: Formlets.XmlWriter.tag
val t : string
type: string
implements: System.IComparable
implements: System.ICloneable
implements: System.IConvertible
implements: System.IComparable<string>
implements: seq<char>
implements: System.Collections.IEnumerable
implements: System.IEquatable<string>
val attr : (string * string) list
type: (string * string) list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<string * string>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<string * string>
implements: System.Collections.IEnumerable
val v : 'a XmlWriter
val x : xml_item list
type: xml_item list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<xml_item>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<xml_item>
implements: System.Collections.IEnumerable
namespace System.Xml
namespace System.Xml.Linq
val render : xml_item list -> XDocument
Full name: Formlets.XmlWriter.render
val xml : xml_item list
type: xml_item list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<xml_item>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<xml_item>
implements: System.Collections.IEnumerable
type XDocument =
class
inherit System.Xml.Linq.XContainer
new : unit -> System.Xml.Linq.XDocument
new : obj [] -> System.Xml.Linq.XDocument
new : System.Xml.Linq.XDeclaration * obj [] -> System.Xml.Linq.XDocument
new : System.Xml.Linq.XDocument -> System.Xml.Linq.XDocument
member Declaration : System.Xml.Linq.XDeclaration with get, set
member DocumentType : System.Xml.Linq.XDocumentType
member NodeType : System.Xml.XmlNodeType
member Root : System.Xml.Linq.XElement
member Save : string -> unit
member Save : System.IO.TextWriter -> unit
member Save : System.Xml.XmlWriter -> unit
member Save : string * System.Xml.Linq.SaveOptions -> unit
member Save : System.IO.TextWriter * System.Xml.Linq.SaveOptions -> unit
member WriteTo : System.Xml.XmlWriter -> unit
static member Load : string -> System.Xml.Linq.XDocument
static member Load : System.IO.TextReader -> System.Xml.Linq.XDocument
static member Load : System.Xml.XmlReader -> System.Xml.Linq.XDocument
static member Load : string * System.Xml.Linq.LoadOptions -> System.Xml.Linq.XDocument
static member Load : System.IO.TextReader * System.Xml.Linq.LoadOptions -> System.Xml.Linq.XDocument
static member Load : System.Xml.XmlReader * System.Xml.Linq.LoadOptions -> System.Xml.Linq.XDocument
static member Parse : string -> System.Xml.Linq.XDocument
static member Parse : string * System.Xml.Linq.LoadOptions -> System.Xml.Linq.XDocument
end
Full name: System.Xml.Linq.XDocument
type: XDocument
implements: System.Xml.IXmlLineInfo
inherits: XContainer
inherits: XNode
inherits: XObject
type XName =
class
member Equals : obj -> bool
member GetHashCode : unit -> int
member LocalName : string
member Namespace : System.Xml.Linq.XNamespace
member NamespaceName : string
member ToString : unit -> string
static member Get : string -> System.Xml.Linq.XName
static member Get : string * string -> System.Xml.Linq.XName
end
Full name: System.Xml.Linq.XName
type: XName
implements: System.IEquatable<XName>
implements: System.Runtime.Serialization.ISerializable
XName.op_Implicit(expandedName: string) : XName
val xtext : (string -> XObject)
type XText =
class
inherit System.Xml.Linq.XNode
new : string -> System.Xml.Linq.XText
new : System.Xml.Linq.XText -> System.Xml.Linq.XText
member NodeType : System.Xml.XmlNodeType
member Value : string with get, set
member WriteTo : System.Xml.XmlWriter -> unit
end
Full name: System.Xml.Linq.XText
type: XText
implements: System.Xml.IXmlLineInfo
inherits: XNode
inherits: XObject
type XObject =
class
member AddAnnotation : obj -> unit
member Annotation<'T> : unit -> 'T
member Annotation : System.Type -> obj
member Annotations<'T> : unit -> System.Collections.Generic.IEnumerable<'T>
member Annotations : System.Type -> System.Collections.Generic.IEnumerable<obj>
member BaseUri : string
member Document : System.Xml.Linq.XDocument
member NodeType : System.Xml.XmlNodeType
member Parent : System.Xml.Linq.XElement
member RemoveAnnotations<'T> : unit -> unit
member RemoveAnnotations : System.Type -> unit
end
Full name: System.Xml.Linq.XObject
type: XObject
implements: System.Xml.IXmlLineInfo
val xattr : (string * 'a -> XObject)
val name : string
type: string
implements: System.IComparable
implements: System.ICloneable
implements: System.IConvertible
implements: System.IComparable<string>
implements: seq<char>
implements: System.Collections.IEnumerable
implements: System.IEquatable<string>
val value : 'a
type XAttribute =
class
inherit System.Xml.Linq.XObject
new : System.Xml.Linq.XName * obj -> System.Xml.Linq.XAttribute
new : System.Xml.Linq.XAttribute -> System.Xml.Linq.XAttribute
member IsNamespaceDeclaration : bool
member Name : System.Xml.Linq.XName
member NextAttribute : System.Xml.Linq.XAttribute
member NodeType : System.Xml.XmlNodeType
member PreviousAttribute : System.Xml.Linq.XAttribute
member Remove : unit -> unit
member SetValue : obj -> unit
member ToString : unit -> string
member Value : string with get, set
static member EmptySequence : System.Collections.Generic.IEnumerable<System.Xml.Linq.XAttribute>
end
Full name: System.Xml.Linq.XAttribute
type: XAttribute
implements: System.Xml.IXmlLineInfo
inherits: XObject
val xattrs : ((string * 'a) list -> XObject list)
val attr : (string * 'a) list
type: (string * 'a) list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<string * 'a>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<string * 'a>
implements: System.Collections.IEnumerable
val map : ('T -> 'U) -> 'T list -> 'U list
Full name: Microsoft.FSharp.Collections.List.map
val xelem : (string -> 'a list -> 'a list -> XObject)
val attr : 'a list
type: 'a list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<'a>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<'a>
implements: System.Collections.IEnumerable
val children : 'a list
type: 'a list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<'a>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<'a>
implements: System.Collections.IEnumerable
type XElement =
class
inherit System.Xml.Linq.XContainer
new : System.Xml.Linq.XName -> System.Xml.Linq.XElement
new : System.Xml.Linq.XName * obj -> System.Xml.Linq.XElement
new : System.Xml.Linq.XName * obj [] -> System.Xml.Linq.XElement
new : System.Xml.Linq.XElement -> System.Xml.Linq.XElement
new : System.Xml.Linq.XStreamingElement -> System.Xml.Linq.XElement
member AncestorsAndSelf : unit -> System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>
member AncestorsAndSelf : System.Xml.Linq.XName -> System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>
member Attribute : System.Xml.Linq.XName -> System.Xml.Linq.XAttribute
member Attributes : unit -> System.Collections.Generic.IEnumerable<System.Xml.Linq.XAttribute>
member Attributes : System.Xml.Linq.XName -> System.Collections.Generic.IEnumerable<System.Xml.Linq.XAttribute>
member DescendantNodesAndSelf : unit -> System.Collections.Generic.IEnumerable<System.Xml.Linq.XNode>
member DescendantsAndSelf : unit -> System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>
member DescendantsAndSelf : System.Xml.Linq.XName -> System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>
member FirstAttribute : System.Xml.Linq.XAttribute
member GetDefaultNamespace : unit -> System.Xml.Linq.XNamespace
member GetNamespaceOfPrefix : string -> System.Xml.Linq.XNamespace
member GetPrefixOfNamespace : System.Xml.Linq.XNamespace -> string
member HasAttributes : bool
member HasElements : bool
member IsEmpty : bool
member LastAttribute : System.Xml.Linq.XAttribute
member Name : System.Xml.Linq.XName with get, set
member NodeType : System.Xml.XmlNodeType
member RemoveAll : unit -> unit
member RemoveAttributes : unit -> unit
member ReplaceAll : obj -> unit
member ReplaceAll : obj [] -> unit
member ReplaceAttributes : obj -> unit
member ReplaceAttributes : obj [] -> unit
member Save : string -> unit
member Save : System.IO.TextWriter -> unit
member Save : System.Xml.XmlWriter -> unit
member Save : string * System.Xml.Linq.SaveOptions -> unit
member Save : System.IO.TextWriter * System.Xml.Linq.SaveOptions -> unit
member SetAttributeValue : System.Xml.Linq.XName * obj -> unit
member SetElementValue : System.Xml.Linq.XName * obj -> unit
member SetValue : obj -> unit
member Value : string with get, set
member WriteTo : System.Xml.XmlWriter -> unit
static member EmptySequence : System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>
static member Load : string -> System.Xml.Linq.XElement
static member Load : System.IO.TextReader -> System.Xml.Linq.XElement
static member Load : System.Xml.XmlReader -> System.Xml.Linq.XElement
static member Load : string * System.Xml.Linq.LoadOptions -> System.Xml.Linq.XElement
static member Load : System.IO.TextReader * System.Xml.Linq.LoadOptions -> System.Xml.Linq.XElement
static member Load : System.Xml.XmlReader * System.Xml.Linq.LoadOptions -> System.Xml.Linq.XElement
static member Parse : string -> System.Xml.Linq.XElement
static member Parse : string * System.Xml.Linq.LoadOptions -> System.Xml.Linq.XElement
end
Full name: System.Xml.Linq.XElement
type: XElement
implements: System.Xml.IXmlLineInfo
implements: System.Xml.Serialization.IXmlSerializable
inherits: XContainer
inherits: XNode
inherits: XObject
val renderForest : (xml_item list -> XObject list)
val render' : (xml_item -> XObject)
val children : xml_item list
type: xml_item list
implements: System.Collections.IStructuralEquatable
implements: System.IComparable<List<xml_item>>
implements: System.IComparable
implements: System.Collections.IStructuralComparable
implements: System.Collections.Generic.IEnumerable<xml_item>
implements: System.Collections.IEnumerable
val root : XObject
type: XObject
implements: System.Xml.IXmlLineInfo
val puree : 'a -> 'a Environ XmlWriter
Full name: Formlets.EnvironXmlWriter.puree
Multiple items
module Environ
from Formlets
--------------------
type 'a Environ = (string * string) list -> 'a
Full name: Formlets.Environ<_>
Multiple items
module XmlWriter
from Formlets
--------------------
type 'a XmlWriter = xml_item list * 'a
Full name: Formlets.XmlWriter<_>
val f : ('a -> 'b) Environ XmlWriter
val a : 'a Environ XmlWriter
val lift : ('a -> 'b) -> xml_item list * 'a Environ -> 'b Environ XmlWriter
Full name: Formlets.EnvironXmlWriter.lift
val refine : xml_item list * 'a -> 'a Environ XmlWriter
Full name: Formlets.EnvironXmlWriter.refine
val x : 'a XmlWriter
type 'a Formlet = 'a Environ XmlWriter NameGen
Full name: Formlets.Formlet<_>
Multiple items
module NameGen
from Formlets
--------------------
type 'a NameGen = int -> 'a * int
Full name: Formlets.NameGen<_>
type AutoOpenAttribute =
class
inherit System.Attribute
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
member Path : string
end
Full name: Microsoft.FSharp.Core.AutoOpenAttribute
type: AutoOpenAttribute
implements: System.Runtime.InteropServices._Attribute
inherits: System.Attribute
Multiple items
module Formlet
from Formlets
--------------------
type 'a Formlet = 'a Environ XmlWriter NameGen
Full name: Formlets.Formlet<_>
val puree : 'a -> 'a Formlet
Full name: Formlets.Formlet.puree
module EnvironXmlWriter
from Formlets
val f : ('a -> 'b) Formlet
val a : 'a Formlet
val lift : ('a -> 'b) -> 'a Formlet -> 'b Formlet
Full name: Formlets.Formlet.lift
val lift2 : ('a -> 'b -> 'c) -> 'a Formlet -> 'b Formlet -> 'c Formlet
Full name: Formlets.Formlet.lift2
val b : 'b Formlet
val f : 'a Formlet
val a : 'b Formlet
val z : 'b
val z : 'a
val xml : xml_item list -> unit Formlet
Full name: Formlets.Formlet.xml
val text : string -> unit Formlet
Full name: Formlets.Formlet.text
val tag : string -> (string * string) list -> 'a Formlet -> 'a Formlet
Full name: Formlets.Formlet.tag
val input : string Formlet
Full name: Formlets.Formlet.input
val xml : (string -> 'a XmlWriter -> 'a XmlWriter)
val lookup : (string -> string Environ XmlWriter)
val tag : (string -> string Environ XmlWriter)
val br : unit Formlet
Full name: Formlets.Formlet.br
val run : 'a Formlet -> 'a Environ
Full name: Formlets.Formlet.run
val render : 'a Formlet -> XDocument
Full name: Formlets.Formlet.render