mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-26 22:29:01 +00:00
Compare commits
2 Commits
WoofWare.M
...
d86bd743af
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d86bd743af | ||
|
|
dff2431bc8 |
@@ -2,8 +2,8 @@ namespace ConsumePlugin
|
|||||||
|
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
type Const =
|
type Const<'a> =
|
||||||
| Int of int
|
| Verbatim of 'a
|
||||||
| String of string
|
| String of string
|
||||||
|
|
||||||
type PairOpKind =
|
type PairOpKind =
|
||||||
@@ -11,12 +11,12 @@ type PairOpKind =
|
|||||||
| ThenDoSeq
|
| ThenDoSeq
|
||||||
|
|
||||||
[<CreateCatamorphism "TreeCata">]
|
[<CreateCatamorphism "TreeCata">]
|
||||||
type Tree =
|
type Tree<'a> =
|
||||||
| Const of Const
|
| Const of Const<'a>
|
||||||
| Pair of Tree * Tree * PairOpKind
|
| Pair of Tree<'a> * Tree<'a> * PairOpKind
|
||||||
| Sequential of Tree list
|
| Sequential of Tree<'a> list
|
||||||
| Builder of Tree * TreeBuilder
|
| Builder of Tree<'a> * TreeBuilder<'a>
|
||||||
|
|
||||||
and TreeBuilder =
|
and TreeBuilder<'a> =
|
||||||
| Child of TreeBuilder
|
| Child of TreeBuilder<'a>
|
||||||
| Parent of Tree
|
| Parent of Tree<'a>
|
||||||
|
|||||||
@@ -47,6 +47,10 @@
|
|||||||
<Compile Include="GeneratedFileSystem.fs">
|
<Compile Include="GeneratedFileSystem.fs">
|
||||||
<MyriadFile>FSharpForFunAndProfitCata.fs</MyriadFile>
|
<MyriadFile>FSharpForFunAndProfitCata.fs</MyriadFile>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="List.fs" />
|
||||||
|
<Compile Include="ListCata.fs">
|
||||||
|
<MyriadFile>List.fs</MyriadFile>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -50,19 +50,3 @@ type Gift =
|
|||||||
| Wrapped of Gift * WrappingPaperStyle
|
| Wrapped of Gift * WrappingPaperStyle
|
||||||
| Boxed of Gift
|
| Boxed of Gift
|
||||||
| WithACard of Gift * message : string
|
| WithACard of Gift * message : string
|
||||||
|
|
||||||
[<CreateCatamorphism "MyListCata">]
|
|
||||||
type MyList =
|
|
||||||
| Nil
|
|
||||||
| Cons of ConsCase
|
|
||||||
|
|
||||||
and ConsCase =
|
|
||||||
{
|
|
||||||
Head : int
|
|
||||||
Tail : MyList
|
|
||||||
}
|
|
||||||
|
|
||||||
[<CreateCatamorphism "MyList2Cata">]
|
|
||||||
type MyList2 =
|
|
||||||
| Nil
|
|
||||||
| Cons of int * MyList2
|
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ namespace ConsumePlugin
|
|||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Description of how to combine cases during a fold
|
/// Description of how to combine cases during a fold
|
||||||
type TreeBuilderCataCase<'TreeBuilder, 'Tree> =
|
type TreeBuilderCataCase<'a, 'TreeBuilder, 'Tree> =
|
||||||
/// How to operate on the Child case
|
/// How to operate on the Child case
|
||||||
abstract Child : 'TreeBuilder -> 'TreeBuilder
|
abstract Child : 'TreeBuilder -> 'TreeBuilder
|
||||||
/// How to operate on the Parent case
|
/// How to operate on the Parent case
|
||||||
abstract Parent : 'Tree -> 'TreeBuilder
|
abstract Parent : 'Tree -> 'TreeBuilder
|
||||||
|
|
||||||
/// Description of how to combine cases during a fold
|
/// Description of how to combine cases during a fold
|
||||||
type TreeCataCase<'TreeBuilder, 'Tree> =
|
type TreeCataCase<'a, 'TreeBuilder, 'Tree> =
|
||||||
/// How to operate on the Const case
|
/// How to operate on the Const case
|
||||||
abstract Const : Const -> 'Tree
|
abstract Const : Const -> 'Tree
|
||||||
/// How to operate on the Pair case
|
/// How to operate on the Pair case
|
||||||
@@ -30,28 +30,28 @@ type TreeCataCase<'TreeBuilder, 'Tree> =
|
|||||||
abstract Builder : 'Tree -> 'TreeBuilder -> 'Tree
|
abstract Builder : 'Tree -> 'TreeBuilder -> 'Tree
|
||||||
|
|
||||||
/// Specifies how to perform a fold (catamorphism) over the type Tree and its friends.
|
/// Specifies how to perform a fold (catamorphism) over the type Tree and its friends.
|
||||||
type TreeCata<'TreeBuilder, 'Tree> =
|
type TreeCata<'a, 'a, 'TreeBuilder, 'Tree> =
|
||||||
{
|
{
|
||||||
/// How to perform a fold (catamorphism) over the type TreeBuilder
|
/// How to perform a fold (catamorphism) over the type TreeBuilder
|
||||||
TreeBuilder : TreeBuilderCataCase<'TreeBuilder, 'Tree>
|
TreeBuilder : TreeBuilderCataCase<'a, 'TreeBuilder, 'Tree>
|
||||||
/// How to perform a fold (catamorphism) over the type Tree
|
/// How to perform a fold (catamorphism) over the type Tree
|
||||||
Tree : TreeCataCase<'TreeBuilder, 'Tree>
|
Tree : TreeCataCase<'a, 'TreeBuilder, 'Tree>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Methods to perform a catamorphism over the type Tree
|
/// Methods to perform a catamorphism over the type Tree
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module TreeCata =
|
module TreeCata =
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
type private Instruction =
|
type private Instruction<'a, 'a> =
|
||||||
| Process__TreeBuilder of TreeBuilder
|
| Process__TreeBuilder of TreeBuilder<'a>
|
||||||
| Process__Tree of Tree
|
| Process__Tree of Tree<'a>
|
||||||
| TreeBuilder_Child
|
| TreeBuilder_Child
|
||||||
| TreeBuilder_Parent
|
| TreeBuilder_Parent
|
||||||
| Tree_Pair of PairOpKind
|
| Tree_Pair of PairOpKind
|
||||||
| Tree_Sequential of int
|
| Tree_Sequential of int
|
||||||
| Tree_Builder
|
| Tree_Builder
|
||||||
|
|
||||||
let private loop (cata : TreeCata<_, _>) (instructions : ResizeArray<Instruction>) =
|
let private loop (cata : TreeCata<_, _, _, _>) (instructions : ResizeArray<Instruction<_, _>>) =
|
||||||
let treeStack = ResizeArray ()
|
let treeStack = ResizeArray ()
|
||||||
let treeBuilderStack = ResizeArray ()
|
let treeBuilderStack = ResizeArray ()
|
||||||
|
|
||||||
@@ -120,14 +120,18 @@ module TreeCata =
|
|||||||
treeBuilderStack, treeStack
|
treeBuilderStack, treeStack
|
||||||
|
|
||||||
/// Execute the catamorphism.
|
/// Execute the catamorphism.
|
||||||
let runTreeBuilder (cata : TreeCata<'TreeBuilderRet, 'TreeRet>) (x : TreeBuilder) : 'TreeBuilderRet =
|
let runTreeBuilder
|
||||||
|
(cata : TreeCata<'a, 'a, 'TreeBuilderRet, 'TreeRet>)
|
||||||
|
(x : TreeBuilder<'a, 'a>)
|
||||||
|
: 'TreeBuilderRet
|
||||||
|
=
|
||||||
let instructions = ResizeArray ()
|
let instructions = ResizeArray ()
|
||||||
instructions.Add (Instruction.Process__TreeBuilder x)
|
instructions.Add (Instruction.Process__TreeBuilder x)
|
||||||
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
||||||
Seq.exactlyOne treeBuilderRetStack
|
Seq.exactlyOne treeBuilderRetStack
|
||||||
|
|
||||||
/// Execute the catamorphism.
|
/// Execute the catamorphism.
|
||||||
let runTree (cata : TreeCata<'TreeBuilderRet, 'TreeRet>) (x : Tree) : 'TreeRet =
|
let runTree (cata : TreeCata<'a, 'a, 'TreeBuilderRet, 'TreeRet>) (x : Tree<'a, 'a>) : 'TreeRet =
|
||||||
let instructions = ResizeArray ()
|
let instructions = ResizeArray ()
|
||||||
instructions.Add (Instruction.Process__Tree x)
|
instructions.Add (Instruction.Process__Tree x)
|
||||||
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
||||||
|
|||||||
@@ -150,112 +150,3 @@ module GiftCata =
|
|||||||
instructions.Add (Instruction.Process__Gift x)
|
instructions.Add (Instruction.Process__Gift x)
|
||||||
let giftRetStack = loop cata instructions
|
let giftRetStack = loop cata instructions
|
||||||
Seq.exactlyOne giftRetStack
|
Seq.exactlyOne giftRetStack
|
||||||
namespace ConsumePlugin
|
|
||||||
|
|
||||||
open WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
/// Description of how to combine cases during a fold
|
|
||||||
type MyListCataCase<'MyList> =
|
|
||||||
/// How to operate on the Nil case
|
|
||||||
abstract Nil : 'MyList
|
|
||||||
/// How to operate on the Cons case
|
|
||||||
abstract Cons : head : int -> tail : 'MyList -> 'MyList
|
|
||||||
|
|
||||||
/// Specifies how to perform a fold (catamorphism) over the type MyList and its friends.
|
|
||||||
type MyListCata<'MyList> =
|
|
||||||
{
|
|
||||||
/// How to perform a fold (catamorphism) over the type MyList
|
|
||||||
MyList : MyListCataCase<'MyList>
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Methods to perform a catamorphism over the type MyList
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module MyListCata =
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
type private Instruction =
|
|
||||||
| Process__MyList of MyList
|
|
||||||
| MyList_Cons of int
|
|
||||||
|
|
||||||
let private loop (cata : MyListCata<_>) (instructions : ResizeArray<Instruction>) =
|
|
||||||
let myListStack = ResizeArray ()
|
|
||||||
|
|
||||||
while instructions.Count > 0 do
|
|
||||||
let currentInstruction = instructions.[instructions.Count - 1]
|
|
||||||
instructions.RemoveAt (instructions.Count - 1)
|
|
||||||
|
|
||||||
match currentInstruction with
|
|
||||||
| Instruction.Process__MyList x ->
|
|
||||||
match x with
|
|
||||||
| MyList.Nil -> cata.MyList.Nil |> myListStack.Add
|
|
||||||
| MyList.Cons ({
|
|
||||||
Head = head
|
|
||||||
Tail = tail
|
|
||||||
}) ->
|
|
||||||
instructions.Add (Instruction.MyList_Cons (head))
|
|
||||||
instructions.Add (Instruction.Process__MyList tail)
|
|
||||||
| Instruction.MyList_Cons (head) ->
|
|
||||||
let tail = myListStack.[myListStack.Count - 1]
|
|
||||||
myListStack.RemoveAt (myListStack.Count - 1)
|
|
||||||
cata.MyList.Cons head tail |> myListStack.Add
|
|
||||||
|
|
||||||
myListStack
|
|
||||||
|
|
||||||
/// Execute the catamorphism.
|
|
||||||
let runMyList (cata : MyListCata<'MyListRet>) (x : MyList) : 'MyListRet =
|
|
||||||
let instructions = ResizeArray ()
|
|
||||||
instructions.Add (Instruction.Process__MyList x)
|
|
||||||
let myListRetStack = loop cata instructions
|
|
||||||
Seq.exactlyOne myListRetStack
|
|
||||||
namespace ConsumePlugin
|
|
||||||
|
|
||||||
open WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
/// Description of how to combine cases during a fold
|
|
||||||
type MyList2CataCase<'MyList2> =
|
|
||||||
/// How to operate on the Nil case
|
|
||||||
abstract Nil : 'MyList2
|
|
||||||
/// How to operate on the Cons case
|
|
||||||
abstract Cons : int -> 'MyList2 -> 'MyList2
|
|
||||||
|
|
||||||
/// Specifies how to perform a fold (catamorphism) over the type MyList2 and its friends.
|
|
||||||
type MyList2Cata<'MyList2> =
|
|
||||||
{
|
|
||||||
/// How to perform a fold (catamorphism) over the type MyList2
|
|
||||||
MyList2 : MyList2CataCase<'MyList2>
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Methods to perform a catamorphism over the type MyList2
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module MyList2Cata =
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
type private Instruction =
|
|
||||||
| Process__MyList2 of MyList2
|
|
||||||
| MyList2_Cons of int
|
|
||||||
|
|
||||||
let private loop (cata : MyList2Cata<_>) (instructions : ResizeArray<Instruction>) =
|
|
||||||
let myList2Stack = ResizeArray ()
|
|
||||||
|
|
||||||
while instructions.Count > 0 do
|
|
||||||
let currentInstruction = instructions.[instructions.Count - 1]
|
|
||||||
instructions.RemoveAt (instructions.Count - 1)
|
|
||||||
|
|
||||||
match currentInstruction with
|
|
||||||
| Instruction.Process__MyList2 x ->
|
|
||||||
match x with
|
|
||||||
| MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add
|
|
||||||
| MyList2.Cons (arg0_0, arg1_0) ->
|
|
||||||
instructions.Add (Instruction.MyList2_Cons (arg0_0))
|
|
||||||
instructions.Add (Instruction.Process__MyList2 arg1_0)
|
|
||||||
| Instruction.MyList2_Cons (arg0_0) ->
|
|
||||||
let arg1_0 = myList2Stack.[myList2Stack.Count - 1]
|
|
||||||
myList2Stack.RemoveAt (myList2Stack.Count - 1)
|
|
||||||
cata.MyList2.Cons arg0_0 arg1_0 |> myList2Stack.Add
|
|
||||||
|
|
||||||
myList2Stack
|
|
||||||
|
|
||||||
/// Execute the catamorphism.
|
|
||||||
let runMyList2 (cata : MyList2Cata<'MyList2Ret>) (x : MyList2) : 'MyList2Ret =
|
|
||||||
let instructions = ResizeArray ()
|
|
||||||
instructions.Add (Instruction.Process__MyList2 x)
|
|
||||||
let myList2RetStack = loop cata instructions
|
|
||||||
Seq.exactlyOne myList2RetStack
|
|
||||||
|
|||||||
19
ConsumePlugin/List.fs
Normal file
19
ConsumePlugin/List.fs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
namespace ConsumePlugin
|
||||||
|
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
[<CreateCatamorphism "MyListCata">]
|
||||||
|
type MyList<'a> =
|
||||||
|
| Nil
|
||||||
|
| Cons of ConsCase<'a>
|
||||||
|
|
||||||
|
and ConsCase<'a> =
|
||||||
|
{
|
||||||
|
Head : 'a
|
||||||
|
Tail : MyList<'a>
|
||||||
|
}
|
||||||
|
|
||||||
|
[<CreateCatamorphism "MyList2Cata">]
|
||||||
|
type MyList2<'a> =
|
||||||
|
| Nil
|
||||||
|
| Cons of 'a * MyList2<'a>
|
||||||
118
ConsumePlugin/ListCata.fs
Normal file
118
ConsumePlugin/ListCata.fs
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// This code was generated by myriad.
|
||||||
|
// Changes to this file will be lost when the code is regenerated.
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace ConsumePlugin
|
||||||
|
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
/// Description of how to combine cases during a fold
|
||||||
|
type MyListCataCase<'a, 'MyList> =
|
||||||
|
/// How to operate on the Nil case
|
||||||
|
abstract Nil : 'MyList
|
||||||
|
/// How to operate on the Cons case
|
||||||
|
abstract Cons : head : 'a -> tail : 'MyList -> 'MyList
|
||||||
|
|
||||||
|
/// Specifies how to perform a fold (catamorphism) over the type MyList and its friends.
|
||||||
|
type MyListCata<'a, 'MyList> =
|
||||||
|
{
|
||||||
|
/// How to perform a fold (catamorphism) over the type MyList
|
||||||
|
MyList : MyListCataCase<'a, 'MyList>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Methods to perform a catamorphism over the type MyList
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module MyListCata =
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
type private Instruction<'a> =
|
||||||
|
| Process__MyList of MyList<'a>
|
||||||
|
| MyList_Cons of 'a
|
||||||
|
|
||||||
|
let private loop (cata : MyListCata<_, _>) (instructions : ResizeArray<Instruction<_>>) =
|
||||||
|
let myListStack = ResizeArray ()
|
||||||
|
|
||||||
|
while instructions.Count > 0 do
|
||||||
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
|
match currentInstruction with
|
||||||
|
| Instruction.Process__MyList x ->
|
||||||
|
match x with
|
||||||
|
| MyList.Nil -> cata.MyList.Nil |> myListStack.Add
|
||||||
|
| MyList.Cons ({
|
||||||
|
Head = head
|
||||||
|
Tail = tail
|
||||||
|
}) ->
|
||||||
|
instructions.Add (Instruction.MyList_Cons (head))
|
||||||
|
instructions.Add (Instruction.Process__MyList tail)
|
||||||
|
| Instruction.MyList_Cons (head) ->
|
||||||
|
let tail = myListStack.[myListStack.Count - 1]
|
||||||
|
myListStack.RemoveAt (myListStack.Count - 1)
|
||||||
|
cata.MyList.Cons head tail |> myListStack.Add
|
||||||
|
|
||||||
|
myListStack
|
||||||
|
|
||||||
|
/// Execute the catamorphism.
|
||||||
|
let runMyList (cata : MyListCata<'a, 'MyListRet>) (x : MyList<'a>) : 'MyListRet =
|
||||||
|
let instructions = ResizeArray ()
|
||||||
|
instructions.Add (Instruction.Process__MyList x)
|
||||||
|
let myListRetStack = loop cata instructions
|
||||||
|
Seq.exactlyOne myListRetStack
|
||||||
|
namespace ConsumePlugin
|
||||||
|
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
/// Description of how to combine cases during a fold
|
||||||
|
type MyList2CataCase<'a, 'MyList2> =
|
||||||
|
/// How to operate on the Nil case
|
||||||
|
abstract Nil : 'MyList2
|
||||||
|
/// How to operate on the Cons case
|
||||||
|
abstract Cons : 'a -> 'MyList2 -> 'MyList2
|
||||||
|
|
||||||
|
/// Specifies how to perform a fold (catamorphism) over the type MyList2 and its friends.
|
||||||
|
type MyList2Cata<'a, 'MyList2> =
|
||||||
|
{
|
||||||
|
/// How to perform a fold (catamorphism) over the type MyList2
|
||||||
|
MyList2 : MyList2CataCase<'a, 'MyList2>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Methods to perform a catamorphism over the type MyList2
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module MyList2Cata =
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
type private Instruction<'a> =
|
||||||
|
| Process__MyList2 of MyList2<'a>
|
||||||
|
| MyList2_Cons of 'a
|
||||||
|
|
||||||
|
let private loop (cata : MyList2Cata<_, _>) (instructions : ResizeArray<Instruction<_>>) =
|
||||||
|
let myList2Stack = ResizeArray ()
|
||||||
|
|
||||||
|
while instructions.Count > 0 do
|
||||||
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
|
match currentInstruction with
|
||||||
|
| Instruction.Process__MyList2 x ->
|
||||||
|
match x with
|
||||||
|
| MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add
|
||||||
|
| MyList2.Cons (arg0_0, arg1_0) ->
|
||||||
|
instructions.Add (Instruction.MyList2_Cons (arg0_0))
|
||||||
|
instructions.Add (Instruction.Process__MyList2 arg1_0)
|
||||||
|
| Instruction.MyList2_Cons (arg0_0) ->
|
||||||
|
let arg1_0 = myList2Stack.[myList2Stack.Count - 1]
|
||||||
|
myList2Stack.RemoveAt (myList2Stack.Count - 1)
|
||||||
|
cata.MyList2.Cons arg0_0 arg1_0 |> myList2Stack.Add
|
||||||
|
|
||||||
|
myList2Stack
|
||||||
|
|
||||||
|
/// Execute the catamorphism.
|
||||||
|
let runMyList2 (cata : MyList2Cata<'a, 'MyList2Ret>) (x : MyList2<'a>) : 'MyList2Ret =
|
||||||
|
let instructions = ResizeArray ()
|
||||||
|
instructions.Add (Instruction.Process__MyList2 x)
|
||||||
|
let myList2RetStack = loop cata instructions
|
||||||
|
Seq.exactlyOne myList2RetStack
|
||||||
@@ -8,10 +8,10 @@ open ConsumePlugin
|
|||||||
[<TestFixture>]
|
[<TestFixture>]
|
||||||
module TestMyList =
|
module TestMyList =
|
||||||
|
|
||||||
let idCata : MyListCata<_> =
|
let idCata<'a> : MyListCata<'a, _> =
|
||||||
{
|
{
|
||||||
MyList =
|
MyList =
|
||||||
{ new MyListCataCase<_> with
|
{ new MyListCataCase<'a, _> with
|
||||||
member _.Nil = MyList.Nil
|
member _.Nil = MyList.Nil
|
||||||
|
|
||||||
member _.Cons head tail =
|
member _.Cons head tail =
|
||||||
@@ -26,31 +26,28 @@ module TestMyList =
|
|||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Cata works`` () =
|
let ``Cata works`` () =
|
||||||
let property (x : MyList) = MyListCata.runMyList idCata x = x
|
let property (x : MyList<int>) = MyListCata.runMyList idCata x = x
|
||||||
|
|
||||||
Check.QuickThrowOnFailure property
|
Check.QuickThrowOnFailure property
|
||||||
|
|
||||||
let toListCata =
|
let toListCata<'a> =
|
||||||
{
|
{
|
||||||
MyList =
|
MyList =
|
||||||
{ new MyListCataCase<int list> with
|
{ new MyListCataCase<'a, 'a list> with
|
||||||
member _.Nil = []
|
member _.Nil = []
|
||||||
member _.Cons (head : int) (tail : int list) = head :: tail
|
member _.Cons (head : 'a) (tail : 'a list) = head :: tail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let toListViaCata (l : MyList) : int list = MyListCata.runMyList toListCata l
|
let toListViaCata<'a> (l : MyList<'a>) : 'a list = MyListCata.runMyList toListCata l
|
||||||
|
|
||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Example of a fold converting to a new data structure`` () =
|
let ``Example of a fold converting to a new data structure`` () =
|
||||||
let rec toListNaive (l : MyList) : int list =
|
let rec toListNaive (l : MyList<int>) : int list =
|
||||||
match l with
|
match l with
|
||||||
| MyList.Nil -> []
|
| MyList.Nil -> []
|
||||||
| MyList.Cons {
|
| MyList.Cons consCell -> consCell.Head :: toListNaive consCell.Tail
|
||||||
Head = head
|
|
||||||
Tail = tail
|
|
||||||
} -> head :: toListNaive tail
|
|
||||||
|
|
||||||
Check.QuickThrowOnFailure (fun l -> toListNaive l = toListViaCata l)
|
Check.QuickThrowOnFailure (fun l -> toListNaive l = toListViaCata l)
|
||||||
|
|
||||||
@@ -62,20 +59,20 @@ module TestMyList =
|
|||||||
let sumCata =
|
let sumCata =
|
||||||
{
|
{
|
||||||
MyList =
|
MyList =
|
||||||
{ new MyListCataCase<int64> with
|
{ new MyListCataCase<int, int64> with
|
||||||
member _.Nil = baseCase
|
member _.Nil = baseCase
|
||||||
member _.Cons (head : int) (tail : int64) = atLeaf head tail
|
member _.Cons (head : int) (tail : int64) = atLeaf head tail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let viaCata (l : MyList) : int64 = MyListCata.runMyList sumCata l
|
let viaCata (l : MyList<int>) : int64 = MyListCata.runMyList sumCata l
|
||||||
|
|
||||||
let viaFold (l : MyList) : int64 =
|
let viaFold (l : MyList<int>) : int64 =
|
||||||
// choose your favourite "to list" method - here I use the cata
|
// choose your favourite "to list" method - here I use the cata
|
||||||
// but that could have been done naively
|
// but that could have been done naively
|
||||||
(toListViaCata l, baseCase)
|
(toListViaCata l, baseCase)
|
||||||
||> List.foldBack (fun elt state -> atLeaf elt state)
|
||> List.foldBack (fun elt state -> atLeaf elt state)
|
||||||
|
|
||||||
let property (l : MyList) = viaCata l = viaFold l
|
let property (l : MyList<int>) = viaCata l = viaFold l
|
||||||
|
|
||||||
Check.QuickThrowOnFailure property
|
Check.QuickThrowOnFailure property
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ open ConsumePlugin
|
|||||||
[<TestFixture>]
|
[<TestFixture>]
|
||||||
module TestMyList2 =
|
module TestMyList2 =
|
||||||
|
|
||||||
let idCata : MyList2Cata<_> =
|
let idCata<'a> : MyList2Cata<'a, _> =
|
||||||
{
|
{
|
||||||
MyList2 =
|
MyList2 =
|
||||||
{ new MyList2CataCase<_> with
|
{ new MyList2CataCase<'a, _> with
|
||||||
member _.Nil = MyList2.Nil
|
member _.Nil = MyList2.Nil
|
||||||
|
|
||||||
member _.Cons head tail = MyList2.Cons (head, tail)
|
member _.Cons head tail = MyList2.Cons (head, tail)
|
||||||
@@ -21,6 +21,6 @@ module TestMyList2 =
|
|||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Cata works`` () =
|
let ``Cata works`` () =
|
||||||
let property (x : MyList2) = MyList2Cata.runMyList2 idCata x = x
|
let property (x : MyList2<int>) = MyList2Cata.runMyList2 idCata x = x
|
||||||
|
|
||||||
Check.QuickThrowOnFailure property
|
Check.QuickThrowOnFailure property
|
||||||
|
|||||||
@@ -400,26 +400,47 @@ module internal AstHelper =
|
|||||||
Accessibility = accessibility
|
Accessibility = accessibility
|
||||||
}
|
}
|
||||||
|
|
||||||
let getUnionCases (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : AdtProduct list =
|
let getUnionCases
|
||||||
|
(SynTypeDefn.SynTypeDefn (info, repr, _, _, _, _))
|
||||||
|
: AdtProduct list * SynTyparDecl list * SynAccess option
|
||||||
|
=
|
||||||
|
let typars, access =
|
||||||
|
match info with
|
||||||
|
| SynComponentInfo (_, typars, _, _, _, _, access, _) -> typars, access
|
||||||
|
|
||||||
|
let typars =
|
||||||
|
match typars with
|
||||||
|
| None -> []
|
||||||
|
| Some (SynTyparDecls.PrefixList (decls, _)) -> decls
|
||||||
|
| Some (SynTyparDecls.SinglePrefix (l, _)) -> [ l ]
|
||||||
|
| Some (SynTyparDecls.PostfixList (decls, constraints, _)) ->
|
||||||
|
if not constraints.IsEmpty then
|
||||||
|
failwith "Constrained type parameters not currently supported"
|
||||||
|
|
||||||
|
decls
|
||||||
|
|
||||||
match repr with
|
match repr with
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_, cases, _), _) ->
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_, cases, _), _) ->
|
||||||
cases
|
let cases =
|
||||||
|> List.map (fun (SynUnionCase.SynUnionCase (_, ident, kind, _, _, _, _)) ->
|
cases
|
||||||
match kind with
|
|> List.map (fun (SynUnionCase.SynUnionCase (_, ident, kind, _, _, _, _)) ->
|
||||||
| SynUnionCaseKind.FullType _ -> failwith "FullType union cases not supported"
|
match kind with
|
||||||
| SynUnionCaseKind.Fields fields ->
|
| SynUnionCaseKind.FullType _ -> failwith "FullType union cases not supported"
|
||||||
{
|
| SynUnionCaseKind.Fields fields ->
|
||||||
Name = ident
|
{
|
||||||
Fields =
|
Name = ident
|
||||||
fields
|
Fields =
|
||||||
|> List.map (fun (SynField.SynField (_, _, id, ty, _, _, _, _, _)) ->
|
fields
|
||||||
{
|
|> List.map (fun (SynField.SynField (_, _, id, ty, _, _, _, _, _)) ->
|
||||||
Type = ty
|
{
|
||||||
Name = id
|
Type = ty
|
||||||
}
|
Name = id
|
||||||
)
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
cases, typars, access
|
||||||
| _ -> failwithf "Failed to get union cases for type that was: %+A" repr
|
| _ -> failwithf "Failed to get union cases for type that was: %+A" repr
|
||||||
|
|
||||||
let getRecordFields (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : AdtNode list =
|
let getRecordFields (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : AdtNode list =
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ module internal CataGenerator =
|
|||||||
/// The relationship this field has with the parent type (or the
|
/// The relationship this field has with the parent type (or the
|
||||||
/// recursive knot of parent types)
|
/// recursive knot of parent types)
|
||||||
Description : FieldDescription
|
Description : FieldDescription
|
||||||
|
/// Any generic parameters this field consumes
|
||||||
|
RequiredGenerics : SynType list option
|
||||||
}
|
}
|
||||||
|
|
||||||
type CataUnionRecordField = (Ident * CataUnionBasicField) list
|
type CataUnionRecordField = (Ident * CataUnionBasicField) list
|
||||||
@@ -81,6 +83,8 @@ module internal CataGenerator =
|
|||||||
/// recursive knot), this is everything we need to know about it for the cata.
|
/// recursive knot), this is everything we need to know about it for the cata.
|
||||||
type UnionAnalysis =
|
type UnionAnalysis =
|
||||||
{
|
{
|
||||||
|
Accessibility : SynAccess option
|
||||||
|
Typars : SynTyparDecl list
|
||||||
/// The name of the stack we'll use for the results
|
/// The name of the stack we'll use for the results
|
||||||
/// of returning from a descent into this union type,
|
/// of returning from a descent into this union type,
|
||||||
/// when performing the cata
|
/// when performing the cata
|
||||||
@@ -112,7 +116,8 @@ module internal CataGenerator =
|
|||||||
/// Seq.exactlyOne {relevantTypar}Stack
|
/// Seq.exactlyOne {relevantTypar}Stack
|
||||||
let createRunFunction
|
let createRunFunction
|
||||||
(cataName : Ident)
|
(cataName : Ident)
|
||||||
(allTypars : SynType list)
|
(userProvidedTypars : SynTyparDecl list)
|
||||||
|
(allArtificialTypars : SynType list)
|
||||||
(relevantTypar : SynType)
|
(relevantTypar : SynType)
|
||||||
(unionType : SynTypeDefn)
|
(unionType : SynTypeDefn)
|
||||||
: SynBinding
|
: SynBinding
|
||||||
@@ -121,19 +126,58 @@ module internal CataGenerator =
|
|||||||
match unionType with
|
match unionType with
|
||||||
| SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (longId = id), _, _, _, _, _) -> List.last id
|
| SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (longId = id), _, _, _, _, _) -> List.last id
|
||||||
|
|
||||||
let allTyparNames =
|
let allArtificialTyparNames =
|
||||||
allTypars
|
allArtificialTypars
|
||||||
|> List.map (fun ty ->
|
|> List.map (fun ty ->
|
||||||
match ty with
|
match ty with
|
||||||
| SynType.Var (SynTypar.SynTypar (ident = ident), _) -> ident
|
| SynType.Var (SynTypar.SynTypar (ident = ident), _) -> ident
|
||||||
| _ -> failwith "logic error in generator"
|
| _ -> failwith "logic error in generator"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let userProvidedTypars =
|
||||||
|
userProvidedTypars
|
||||||
|
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, ty)) -> SynType.Var (ty, range0))
|
||||||
|
|
||||||
let relevantTyparName =
|
let relevantTyparName =
|
||||||
match relevantTypar with
|
match relevantTypar with
|
||||||
| SynType.Var (SynTypar.SynTypar (ident = ident), _) -> ident
|
| SynType.Var (SynTypar.SynTypar (ident = ident), _) -> ident
|
||||||
| _ -> failwith "logic error in generator"
|
| _ -> failwith "logic error in generator"
|
||||||
|
|
||||||
|
let inputObjectType =
|
||||||
|
let baseType =
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ relevantTypeName ])
|
||||||
|
|
||||||
|
if userProvidedTypars.Length = 0 then
|
||||||
|
baseType
|
||||||
|
else
|
||||||
|
SynType.App (
|
||||||
|
baseType,
|
||||||
|
Some range0,
|
||||||
|
userProvidedTypars,
|
||||||
|
List.replicate (userProvidedTypars.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
|
// The object on which we'll run the cata
|
||||||
|
let inputObject =
|
||||||
|
SynPat.CreateTyped (SynPat.CreateNamed (Ident.Create "x"), inputObjectType)
|
||||||
|
|
||||||
|
let cataObject =
|
||||||
|
SynPat.CreateTyped (
|
||||||
|
SynPat.CreateNamed (Ident.Create "cata"),
|
||||||
|
SynType.App (
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataName ]),
|
||||||
|
Some range0,
|
||||||
|
userProvidedTypars @ allArtificialTypars,
|
||||||
|
List.replicate (userProvidedTypars.Length + allArtificialTypars.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
SynBinding.SynBinding (
|
SynBinding.SynBinding (
|
||||||
None,
|
None,
|
||||||
SynBindingKind.Normal,
|
SynBindingKind.Normal,
|
||||||
@@ -151,28 +195,7 @@ module internal CataGenerator =
|
|||||||
),
|
),
|
||||||
SynPat.CreateLongIdent (
|
SynPat.CreateLongIdent (
|
||||||
SynLongIdent.CreateString ("run" + relevantTypeName.idText),
|
SynLongIdent.CreateString ("run" + relevantTypeName.idText),
|
||||||
[
|
[ SynPat.CreateParen (cataObject) ; SynPat.CreateParen inputObject ]
|
||||||
SynPat.CreateParen (
|
|
||||||
SynPat.CreateTyped (
|
|
||||||
SynPat.CreateNamed (Ident.Create "cata"),
|
|
||||||
SynType.App (
|
|
||||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataName ]),
|
|
||||||
Some range0,
|
|
||||||
allTypars,
|
|
||||||
List.replicate (allTypars.Length - 1) range0,
|
|
||||||
Some range0,
|
|
||||||
false,
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
SynPat.CreateParen (
|
|
||||||
SynPat.CreateTyped (
|
|
||||||
SynPat.CreateNamed (Ident.Create "x"),
|
|
||||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ relevantTypeName ])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
),
|
||||||
Some (SynBindingReturnInfo.Create relevantTypar),
|
Some (SynBindingReturnInfo.Create relevantTypar),
|
||||||
SynExpr.CreateTyped (
|
SynExpr.CreateTyped (
|
||||||
@@ -219,8 +242,8 @@ module internal CataGenerator =
|
|||||||
Ident.Create (t.idText + "Stack") |> Ident.lowerFirstLetter
|
Ident.Create (t.idText + "Stack") |> Ident.lowerFirstLetter
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
allTyparNames,
|
allArtificialTyparNames,
|
||||||
List.replicate (allTypars.Length - 1) range0,
|
List.replicate (allArtificialTyparNames.Length - 1) range0,
|
||||||
range0
|
range0
|
||||||
),
|
),
|
||||||
expr =
|
expr =
|
||||||
@@ -262,9 +285,10 @@ module internal CataGenerator =
|
|||||||
match ty with
|
match ty with
|
||||||
| SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (_, _, _, id, _, _, _, _), _, _, _, _, _) -> id
|
| SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (_, _, _, id, _, _, _, _), _, _, _, _, _) -> id
|
||||||
|
|
||||||
let getNameUnion (unionType : SynType) : LongIdent option =
|
let rec getNameUnion (unionType : SynType) : LongIdent option =
|
||||||
match unionType with
|
match unionType with
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) -> Some name
|
| SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) -> Some name
|
||||||
|
| SynType.App (ty, _, _, _, _, _, _) -> getNameUnion ty
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
|
||||||
let getNameKey (ty : SynTypeDefn) : string =
|
let getNameKey (ty : SynTypeDefn) : string =
|
||||||
@@ -286,44 +310,8 @@ module internal CataGenerator =
|
|||||||
: CataUnionBasicField list
|
: CataUnionBasicField list
|
||||||
=
|
=
|
||||||
let rec go (prefix : string) (name : Ident option) (ty : SynType) : CataUnionBasicField =
|
let rec go (prefix : string) (name : Ident option) (ty : SynType) : CataUnionBasicField =
|
||||||
let stripped = SynType.stripOptionalParen ty
|
let dealWithPrimitive (typeArgs : SynType list option) (ty : SynType) (typeName : LongIdent) =
|
||||||
|
let key = typeName |> List.map _.idText |> String.concat "/"
|
||||||
match stripped with
|
|
||||||
| ListType child ->
|
|
||||||
let gone = go (prefix + "_") None child
|
|
||||||
|
|
||||||
match gone.Description with
|
|
||||||
| FieldDescription.NonRecursive ty ->
|
|
||||||
// Great, no recursion, just treat it as atomic
|
|
||||||
{
|
|
||||||
FieldName = name
|
|
||||||
ArgName =
|
|
||||||
match name with
|
|
||||||
| Some n -> Ident.lowerFirstLetter n
|
|
||||||
| None -> Ident.Create $"arg%s{prefix}"
|
|
||||||
Description = FieldDescription.NonRecursive stripped
|
|
||||||
}
|
|
||||||
| FieldDescription.Self ty ->
|
|
||||||
{
|
|
||||||
FieldName = name
|
|
||||||
ArgName =
|
|
||||||
match name with
|
|
||||||
| Some n -> Ident.lowerFirstLetter n
|
|
||||||
| None -> Ident.Create $"arg%s{prefix}"
|
|
||||||
Description = FieldDescription.ListSelf ty
|
|
||||||
}
|
|
||||||
| FieldDescription.ListSelf _ -> failwith "Deeply nested lists not currently supported"
|
|
||||||
| PrimitiveType _ ->
|
|
||||||
{
|
|
||||||
FieldName = name
|
|
||||||
ArgName =
|
|
||||||
match name with
|
|
||||||
| Some n -> Ident.lowerFirstLetter n
|
|
||||||
| None -> Ident.Create $"arg%s{prefix}"
|
|
||||||
Description = FieldDescription.NonRecursive stripped
|
|
||||||
}
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ty, _, _)) ->
|
|
||||||
let key = ty |> List.map _.idText |> String.concat "/"
|
|
||||||
|
|
||||||
let isKnownUnion =
|
let isKnownUnion =
|
||||||
allUnionTypes |> List.exists (fun unionTy -> getNameKey unionTy = key)
|
allUnionTypes |> List.exists (fun unionTy -> getNameKey unionTy = key)
|
||||||
@@ -339,7 +327,8 @@ module internal CataGenerator =
|
|||||||
match name with
|
match name with
|
||||||
| Some n -> Ident.lowerFirstLetter n
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
| None -> Ident.Create $"arg%s{prefix}"
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
Description = FieldDescription.Self stripped
|
Description = FieldDescription.Self ty
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -348,10 +337,68 @@ module internal CataGenerator =
|
|||||||
match name with
|
match name with
|
||||||
| Some n -> Ident.lowerFirstLetter n
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
| None -> Ident.Create $"arg%s{prefix}"
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
Description = FieldDescription.NonRecursive stripped
|
Description = FieldDescription.NonRecursive ty
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
| _ -> failwithf "Unrecognised type: %+A" stripped
|
let rec dealWithType (typeArgs : SynType list option) (stripped : SynType) =
|
||||||
|
match stripped with
|
||||||
|
| ListType child ->
|
||||||
|
let gone = go (prefix + "_") None child
|
||||||
|
|
||||||
|
match gone.Description with
|
||||||
|
| FieldDescription.NonRecursive ty ->
|
||||||
|
// Great, no recursion, just treat it as atomic
|
||||||
|
{
|
||||||
|
FieldName = name
|
||||||
|
ArgName =
|
||||||
|
match name with
|
||||||
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
|
Description = FieldDescription.NonRecursive stripped
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
|
}
|
||||||
|
| FieldDescription.Self ty ->
|
||||||
|
{
|
||||||
|
FieldName = name
|
||||||
|
ArgName =
|
||||||
|
match name with
|
||||||
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
|
Description = FieldDescription.ListSelf ty
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
|
}
|
||||||
|
| FieldDescription.ListSelf _ -> failwith "Deeply nested lists not currently supported"
|
||||||
|
| PrimitiveType _ ->
|
||||||
|
{
|
||||||
|
FieldName = name
|
||||||
|
ArgName =
|
||||||
|
match name with
|
||||||
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
|
Description = FieldDescription.NonRecursive stripped
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
|
}
|
||||||
|
| SynType.App (ty, _, childTypeArgs, _, _, _, _) ->
|
||||||
|
match typeArgs with
|
||||||
|
| Some _ -> failwithf "Nested applications of types not supported in %+A" ty
|
||||||
|
| None -> dealWithType (Some childTypeArgs) (SynType.stripOptionalParen ty)
|
||||||
|
| SynType.LongIdent (SynLongIdent.SynLongIdent (ty, _, _)) -> dealWithPrimitive typeArgs stripped ty
|
||||||
|
| SynType.Var (typar, _) ->
|
||||||
|
{
|
||||||
|
FieldName = name
|
||||||
|
ArgName =
|
||||||
|
match name with
|
||||||
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
|
Description = FieldDescription.NonRecursive ty
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
| _ -> failwithf "Unrecognised type: %+A" stripped
|
||||||
|
|
||||||
|
let stripped = SynType.stripOptionalParen ty
|
||||||
|
dealWithType None stripped
|
||||||
|
|
||||||
fields |> List.mapi (fun i x -> go $"%i{argIndex}_%i{i}" x.Name x.Type)
|
fields |> List.mapi (fun i x -> go $"%i{argIndex}_%i{i}" x.Name x.Type)
|
||||||
|
|
||||||
@@ -432,7 +479,26 @@ module internal CataGenerator =
|
|||||||
Fields =
|
Fields =
|
||||||
{
|
{
|
||||||
Name = None
|
Name = None
|
||||||
Type = SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent union.ParentTypeName)
|
Type =
|
||||||
|
let name =
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent union.ParentTypeName)
|
||||||
|
|
||||||
|
match union.Typars with
|
||||||
|
| [] -> name
|
||||||
|
| typars ->
|
||||||
|
let typars =
|
||||||
|
typars
|
||||||
|
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.Var (typar, range0))
|
||||||
|
|
||||||
|
SynType.App (
|
||||||
|
name,
|
||||||
|
Some range0,
|
||||||
|
typars,
|
||||||
|
List.replicate (typars.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
}
|
}
|
||||||
@@ -461,10 +527,20 @@ module internal CataGenerator =
|
|||||||
|
|
||||||
let cases = casesFromProcess @ casesFromCases
|
let cases = casesFromProcess @ casesFromCases
|
||||||
|
|
||||||
|
let typars =
|
||||||
|
// TODO: deduplicate names where we have the same generic across multiple DUs
|
||||||
|
analysis
|
||||||
|
|> List.collect _.Typars
|
||||||
|
|> fun x ->
|
||||||
|
if x.IsEmpty then
|
||||||
|
None
|
||||||
|
else
|
||||||
|
Some (SynTyparDecls.PostfixList (x, [], range0))
|
||||||
|
|
||||||
SynTypeDefn.SynTypeDefn (
|
SynTypeDefn.SynTypeDefn (
|
||||||
SynComponentInfo.SynComponentInfo (
|
SynComponentInfo.SynComponentInfo (
|
||||||
[ SynAttributeList.Create [ SynAttribute.RequireQualifiedAccess () ] ],
|
[ SynAttributeList.Create [ SynAttribute.RequireQualifiedAccess () ] ],
|
||||||
None,
|
typars,
|
||||||
[],
|
[],
|
||||||
[ Ident.Create "Instruction" ],
|
[ Ident.Create "Instruction" ],
|
||||||
PreXmlDoc.Empty,
|
PreXmlDoc.Empty,
|
||||||
@@ -514,7 +590,7 @@ module internal CataGenerator =
|
|||||||
let componentInfo =
|
let componentInfo =
|
||||||
SynComponentInfo.SynComponentInfo (
|
SynComponentInfo.SynComponentInfo (
|
||||||
[],
|
[],
|
||||||
Some (SynTyparDecls.PostfixList (orderedGenerics, [], range0)),
|
Some (SynTyparDecls.PostfixList (analysis.Typars @ orderedGenerics, [], range0)),
|
||||||
[],
|
[],
|
||||||
[ analysis.CataTypeName ],
|
[ analysis.CataTypeName ],
|
||||||
// TODO: better docstring
|
// TODO: better docstring
|
||||||
@@ -625,30 +701,32 @@ module internal CataGenerator =
|
|||||||
/// Build a record which contains one of every cata type.
|
/// Build a record which contains one of every cata type.
|
||||||
/// That is, define a type Cata<{'ret<U> for U in T}>
|
/// That is, define a type Cata<{'ret<U> for U in T}>
|
||||||
/// with one member for each U, namely of type [U]Cata<{'ret<U> for U in T}>.
|
/// with one member for each U, namely of type [U]Cata<{'ret<U> for U in T}>.
|
||||||
// TODO: this should take an analysis instead
|
let createCataRecord (cataName : Ident) (doc : PreXmlDoc) (analysis : UnionAnalysis list) : SynTypeDefn =
|
||||||
let createCataRecord (cataName : Ident) (doc : PreXmlDoc) (allUnionTypes : SynTypeDefn list) : SynTypeDefn =
|
// An artificial generic for each union type
|
||||||
let generics =
|
let generics =
|
||||||
allUnionTypes
|
analysis
|
||||||
|> List.map (fun defn ->
|
|> List.map (fun analysis -> SynTypar.SynTypar (analysis.GenericName, TyparStaticReq.None, false))
|
||||||
let name = getName defn |> List.map _.idText |> String.concat "" |> Ident.Create
|
|
||||||
SynTypar.SynTypar (name, TyparStaticReq.None, false)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
// A field for each cata
|
||||||
let fields =
|
let fields =
|
||||||
allUnionTypes
|
analysis
|
||||||
|> List.map (fun unionType ->
|
|> List.map (fun analysis ->
|
||||||
let nameForDoc = List.last (getName unionType) |> _.idText
|
let nameForDoc = List.last(analysis.ParentTypeName).idText
|
||||||
|
|
||||||
let doc =
|
let doc =
|
||||||
PreXmlDoc.Create $" How to perform a fold (catamorphism) over the type %s{nameForDoc}"
|
PreXmlDoc.Create $" How to perform a fold (catamorphism) over the type %s{nameForDoc}"
|
||||||
|
|
||||||
let name = getName unionType
|
let artificialGenerics = generics |> List.map (fun v -> SynType.Var (v, range0))
|
||||||
|
|
||||||
|
let userInputGenerics =
|
||||||
|
analysis.Typars
|
||||||
|
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, typar)) -> SynType.Var (typar, range0))
|
||||||
|
|
||||||
let ty =
|
let ty =
|
||||||
SynType.App (
|
SynType.App (
|
||||||
SynType.CreateLongIdent (SynLongIdent.CreateString (List.last(name).idText + "CataCase")),
|
SynType.LongIdent (SynLongIdent.CreateFromLongIdent [ analysis.CataTypeName ]),
|
||||||
Some range0,
|
Some range0,
|
||||||
generics |> List.map (fun v -> SynType.Var (v, range0)),
|
userInputGenerics @ artificialGenerics,
|
||||||
List.replicate (generics.Length - 1) range0,
|
List.replicate (generics.Length - 1) range0,
|
||||||
Some range0,
|
Some range0,
|
||||||
false,
|
false,
|
||||||
@@ -658,7 +736,7 @@ module internal CataGenerator =
|
|||||||
SynField.SynField (
|
SynField.SynField (
|
||||||
[],
|
[],
|
||||||
false,
|
false,
|
||||||
Some (List.last name),
|
Some (List.last analysis.ParentTypeName),
|
||||||
ty,
|
ty,
|
||||||
false,
|
false,
|
||||||
doc,
|
doc,
|
||||||
@@ -670,16 +748,21 @@ module internal CataGenerator =
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A "real" generic for each generic in the user-provided type
|
||||||
|
let genericsFromUserInput =
|
||||||
|
analysis
|
||||||
|
|> List.collect (fun analysis ->
|
||||||
|
// TODO: deduplicate generics with the same name from different cases
|
||||||
|
analysis.Typars
|
||||||
|
)
|
||||||
|
|
||||||
|
let genericsFromCata =
|
||||||
|
generics |> List.map (fun ty -> SynTyparDecl.SynTyparDecl ([], ty))
|
||||||
|
|
||||||
let componentInfo =
|
let componentInfo =
|
||||||
SynComponentInfo.SynComponentInfo (
|
SynComponentInfo.SynComponentInfo (
|
||||||
[],
|
[],
|
||||||
Some (
|
Some (SynTyparDecls.PostfixList (genericsFromUserInput @ genericsFromCata, [], range0)),
|
||||||
SynTyparDecls.PostfixList (
|
|
||||||
generics |> List.map (fun ty -> SynTyparDecl.SynTyparDecl ([], ty)),
|
|
||||||
[],
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
),
|
|
||||||
[],
|
[],
|
||||||
[ cataName ],
|
[ cataName ],
|
||||||
doc,
|
doc,
|
||||||
@@ -714,13 +797,20 @@ module internal CataGenerator =
|
|||||||
|
|
||||||
allUnionTypes
|
allUnionTypes
|
||||||
|> List.map (fun unionType ->
|
|> List.map (fun unionType ->
|
||||||
|
let cases, typars, access = AstHelper.getUnionCases unionType
|
||||||
|
|
||||||
let cases =
|
let cases =
|
||||||
AstHelper.getUnionCases unionType
|
cases
|
||||||
|> List.map (fun prod ->
|
|> List.map (fun prod ->
|
||||||
let fields =
|
let fields =
|
||||||
prod.Fields
|
prod.Fields
|
||||||
|> List.indexed
|
|> List.indexed
|
||||||
|> List.collect (fun (i, node) ->
|
|> List.collect (fun (i, node) ->
|
||||||
|
let availableGenerics =
|
||||||
|
match node.Type with
|
||||||
|
| SynType.App (_, _, vars, _, _, _, _) -> vars
|
||||||
|
| _ -> []
|
||||||
|
|
||||||
match getNameUnion node.Type with
|
match getNameUnion node.Type with
|
||||||
| None ->
|
| None ->
|
||||||
analyse allRecordTypes allUnionTypes i [ node ] |> List.map CataUnionField.Basic
|
analyse allRecordTypes allUnionTypes i [ node ] |> List.map CataUnionField.Basic
|
||||||
@@ -742,6 +832,8 @@ module internal CataGenerator =
|
|||||||
let unionTypeName = getName unionType
|
let unionTypeName = getName unionType
|
||||||
|
|
||||||
{
|
{
|
||||||
|
Typars = typars
|
||||||
|
Accessibility = access
|
||||||
StackName =
|
StackName =
|
||||||
List.last(getName unionType).idText + "Stack"
|
List.last(getName unionType).idText + "Stack"
|
||||||
|> Ident.Create
|
|> Ident.Create
|
||||||
@@ -1218,6 +1310,23 @@ module internal CataGenerator =
|
|||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A generic for each DU case, and a generic for each generic in the DU
|
||||||
|
let genericCount = analysis.Length + (analysis |> List.sumBy _.Typars.Length)
|
||||||
|
|
||||||
|
let instructionsArrType =
|
||||||
|
if genericCount > analysis.Length then
|
||||||
|
SynType.App (
|
||||||
|
SynType.CreateLongIdent "Instruction",
|
||||||
|
Some range0,
|
||||||
|
List.replicate (genericCount - analysis.Length) (SynType.Anon range0),
|
||||||
|
List.replicate (genericCount - analysis.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
else
|
||||||
|
SynType.CreateLongIdent "Instruction"
|
||||||
|
|
||||||
let headPat =
|
let headPat =
|
||||||
SynPat.LongIdent (
|
SynPat.LongIdent (
|
||||||
SynLongIdent.CreateString "loop",
|
SynLongIdent.CreateString "loop",
|
||||||
@@ -1231,8 +1340,8 @@ module internal CataGenerator =
|
|||||||
SynType.App (
|
SynType.App (
|
||||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataTypeName ]),
|
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataTypeName ]),
|
||||||
Some range0,
|
Some range0,
|
||||||
List.replicate analysis.Length (SynType.Anon range0),
|
List.replicate genericCount (SynType.Anon range0),
|
||||||
List.replicate (analysis.Length - 1) range0,
|
List.replicate (genericCount - 1) range0,
|
||||||
Some range0,
|
Some range0,
|
||||||
false,
|
false,
|
||||||
range0
|
range0
|
||||||
@@ -1245,7 +1354,7 @@ module internal CataGenerator =
|
|||||||
SynType.App (
|
SynType.App (
|
||||||
SynType.CreateLongIdent "ResizeArray",
|
SynType.CreateLongIdent "ResizeArray",
|
||||||
Some range0,
|
Some range0,
|
||||||
[ SynType.CreateLongIdent "Instruction" ],
|
[ instructionsArrType ],
|
||||||
[],
|
[],
|
||||||
Some range0,
|
Some range0,
|
||||||
false,
|
false,
|
||||||
@@ -1404,6 +1513,9 @@ module internal CataGenerator =
|
|||||||
xmldoc = PreXmlDoc.Create $" Methods to perform a catamorphism over the type %s{parentName}"
|
xmldoc = PreXmlDoc.Create $" Methods to perform a catamorphism over the type %s{parentName}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let cataVarName = Ident.Create "cata"
|
||||||
|
let analysis = makeUnionAnalyses cataVarName allRecordTypes allUnionTypes
|
||||||
|
|
||||||
let allTypars =
|
let allTypars =
|
||||||
allUnionTypes
|
allUnionTypes
|
||||||
|> List.map (fun unionType ->
|
|> List.map (fun unionType ->
|
||||||
@@ -1414,12 +1526,14 @@ module internal CataGenerator =
|
|||||||
|> fun x -> SynType.Var (x, range0)
|
|> fun x -> SynType.Var (x, range0)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let userProvidedGenerics = analysis |> List.collect (fun x -> x.Typars)
|
||||||
|
|
||||||
let runFunctions =
|
let runFunctions =
|
||||||
List.zip allUnionTypes allTypars
|
List.zip allUnionTypes allTypars
|
||||||
|> List.map (fun (unionType, relevantTypar) -> createRunFunction cataName allTypars relevantTypar unionType)
|
|> List.map (fun (unionType, relevantTypar) ->
|
||||||
|
createRunFunction cataName userProvidedGenerics allTypars relevantTypar unionType
|
||||||
|
)
|
||||||
|
|
||||||
let cataVarName = Ident.Create "cata"
|
|
||||||
let analysis = makeUnionAnalyses cataVarName allRecordTypes allUnionTypes
|
|
||||||
|
|
||||||
let cataStructures =
|
let cataStructures =
|
||||||
createCataStructure analysis
|
createCataStructure analysis
|
||||||
@@ -1432,7 +1546,7 @@ module internal CataGenerator =
|
|||||||
$" Specifies how to perform a fold (catamorphism) over the type %s{parentName} and its friends."
|
$" Specifies how to perform a fold (catamorphism) over the type %s{parentName} and its friends."
|
||||||
|
|
||||||
let cataRecord =
|
let cataRecord =
|
||||||
SynModuleDecl.Types ([ createCataRecord cataName recordDoc allUnionTypes ], range0)
|
SynModuleDecl.Types ([ createCataRecord cataName recordDoc analysis ], range0)
|
||||||
|
|
||||||
SynModuleOrNamespace.CreateNamespace (
|
SynModuleOrNamespace.CreateNamespace (
|
||||||
ns,
|
ns,
|
||||||
@@ -1453,6 +1567,54 @@ module internal CataGenerator =
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let generate (context : GeneratorContext) : Output =
|
||||||
|
let ast, _ =
|
||||||
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
|
let types = Ast.extractTypeDefn ast
|
||||||
|
|
||||||
|
let opens = AstHelper.extractOpens ast
|
||||||
|
|
||||||
|
let namespaceAndTypes =
|
||||||
|
types
|
||||||
|
|> List.choose (fun (ns, types) ->
|
||||||
|
let typeWithAttr =
|
||||||
|
types
|
||||||
|
|> List.tryPick (fun ty ->
|
||||||
|
match Ast.getAttribute<CreateCatamorphismAttribute> ty with
|
||||||
|
| None -> None
|
||||||
|
| Some attr -> Some (attr.ArgExpr, ty)
|
||||||
|
)
|
||||||
|
|
||||||
|
match typeWithAttr with
|
||||||
|
| Some taggedType ->
|
||||||
|
let unions, records, others =
|
||||||
|
(([], [], []), types)
|
||||||
|
||> List.fold (fun
|
||||||
|
(unions, records, others)
|
||||||
|
(SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _) as ty) ->
|
||||||
|
match repr with
|
||||||
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union _, _) ->
|
||||||
|
ty :: unions, records, others
|
||||||
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record _, _) ->
|
||||||
|
unions, ty :: records, others
|
||||||
|
| _ -> unions, records, ty :: others
|
||||||
|
)
|
||||||
|
|
||||||
|
if not others.IsEmpty then
|
||||||
|
failwith
|
||||||
|
$"Error: all types recursively defined together with a CreateCatamorphism type must be discriminated unions or records. %+A{others}"
|
||||||
|
|
||||||
|
Some (ns, taggedType, unions, records)
|
||||||
|
| _ -> None
|
||||||
|
)
|
||||||
|
|
||||||
|
let modules =
|
||||||
|
namespaceAndTypes
|
||||||
|
|> List.map (fun (ns, taggedType, unions, records) -> createModule opens ns taggedType unions records)
|
||||||
|
|
||||||
|
Output.Ast modules
|
||||||
|
|
||||||
/// Myriad generator that provides a catamorphism for an algebraic data type.
|
/// Myriad generator that provides a catamorphism for an algebraic data type.
|
||||||
[<MyriadGenerator("create-catamorphism")>]
|
[<MyriadGenerator("create-catamorphism")>]
|
||||||
type CreateCatamorphismGenerator () =
|
type CreateCatamorphismGenerator () =
|
||||||
@@ -1460,52 +1622,4 @@ type CreateCatamorphismGenerator () =
|
|||||||
interface IMyriadGenerator with
|
interface IMyriadGenerator with
|
||||||
member _.ValidInputExtensions = [ ".fs" ]
|
member _.ValidInputExtensions = [ ".fs" ]
|
||||||
|
|
||||||
member _.Generate (context : GeneratorContext) =
|
member _.Generate (context : GeneratorContext) = CataGenerator.generate context
|
||||||
let ast, _ =
|
|
||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
|
||||||
|
|
||||||
let types = Ast.extractTypeDefn ast
|
|
||||||
|
|
||||||
let opens = AstHelper.extractOpens ast
|
|
||||||
|
|
||||||
let namespaceAndTypes =
|
|
||||||
types
|
|
||||||
|> List.choose (fun (ns, types) ->
|
|
||||||
let typeWithAttr =
|
|
||||||
types
|
|
||||||
|> List.tryPick (fun ty ->
|
|
||||||
match Ast.getAttribute<CreateCatamorphismAttribute> ty with
|
|
||||||
| None -> None
|
|
||||||
| Some attr -> Some (attr.ArgExpr, ty)
|
|
||||||
)
|
|
||||||
|
|
||||||
match typeWithAttr with
|
|
||||||
| Some taggedType ->
|
|
||||||
let unions, records, others =
|
|
||||||
(([], [], []), types)
|
|
||||||
||> List.fold (fun
|
|
||||||
(unions, records, others)
|
|
||||||
(SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _) as ty) ->
|
|
||||||
match repr with
|
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union _, _) ->
|
|
||||||
ty :: unions, records, others
|
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record _, _) ->
|
|
||||||
unions, ty :: records, others
|
|
||||||
| _ -> unions, records, ty :: others
|
|
||||||
)
|
|
||||||
|
|
||||||
if not others.IsEmpty then
|
|
||||||
failwith
|
|
||||||
$"Error: all types recursively defined together with a CreateCatamorphism type must be discriminated unions or records. %+A{others}"
|
|
||||||
|
|
||||||
Some (ns, taggedType, unions, records)
|
|
||||||
| _ -> None
|
|
||||||
)
|
|
||||||
|
|
||||||
let modules =
|
|
||||||
namespaceAndTypes
|
|
||||||
|> List.map (fun (ns, taggedType, unions, records) ->
|
|
||||||
CataGenerator.createModule opens ns taggedType unions records
|
|
||||||
)
|
|
||||||
|
|
||||||
Output.Ast modules
|
|
||||||
|
|||||||
Reference in New Issue
Block a user