mirror of
				https://github.com/Smaug123/WoofWare.Myriad
				synced 2025-10-27 06:39:00 +00:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			WoofWare.M
			...
			d86bd743af
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | d86bd743af | ||
|  | dff2431bc8 | 
| @@ -2,8 +2,8 @@ namespace ConsumePlugin | ||||
|  | ||||
| open WoofWare.Myriad.Plugins | ||||
|  | ||||
| type Const = | ||||
|     | Int of int | ||||
| type Const<'a> = | ||||
|     | Verbatim of 'a | ||||
|     | String of string | ||||
|  | ||||
| type PairOpKind = | ||||
| @@ -11,12 +11,12 @@ type PairOpKind = | ||||
|     | ThenDoSeq | ||||
|  | ||||
| [<CreateCatamorphism "TreeCata">] | ||||
| type Tree = | ||||
|     | Const of Const | ||||
|     | Pair of Tree * Tree * PairOpKind | ||||
|     | Sequential of Tree list | ||||
|     | Builder of Tree * TreeBuilder | ||||
| type Tree<'a> = | ||||
|     | Const of Const<'a> | ||||
|     | Pair of Tree<'a> * Tree<'a> * PairOpKind | ||||
|     | Sequential of Tree<'a> list | ||||
|     | Builder of Tree<'a> * TreeBuilder<'a> | ||||
|  | ||||
| and TreeBuilder = | ||||
|     | Child of TreeBuilder | ||||
|     | Parent of Tree | ||||
| and TreeBuilder<'a> = | ||||
|     | Child of TreeBuilder<'a> | ||||
|     | Parent of Tree<'a> | ||||
|   | ||||
| @@ -47,6 +47,10 @@ | ||||
|     <Compile Include="GeneratedFileSystem.fs"> | ||||
|       <MyriadFile>FSharpForFunAndProfitCata.fs</MyriadFile> | ||||
|     </Compile> | ||||
|     <Compile Include="List.fs" /> | ||||
|     <Compile Include="ListCata.fs"> | ||||
|       <MyriadFile>List.fs</MyriadFile> | ||||
|     </Compile> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|   | ||||
| @@ -50,19 +50,3 @@ type Gift = | ||||
|     | Wrapped of Gift * WrappingPaperStyle | ||||
|     | Boxed of Gift | ||||
|     | 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 | ||||
|  | ||||
| /// 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 | ||||
|     abstract Child : 'TreeBuilder -> 'TreeBuilder | ||||
|     /// How to operate on the Parent case | ||||
|     abstract Parent : 'Tree -> 'TreeBuilder | ||||
|  | ||||
| /// 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 | ||||
|     abstract Const : Const -> 'Tree | ||||
|     /// How to operate on the Pair case | ||||
| @@ -30,28 +30,28 @@ type TreeCataCase<'TreeBuilder, 'Tree> = | ||||
|     abstract Builder : 'Tree -> 'TreeBuilder -> 'Tree | ||||
|  | ||||
| /// 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 | ||||
|         TreeBuilder : TreeBuilderCataCase<'TreeBuilder, 'Tree> | ||||
|         TreeBuilder : TreeBuilderCataCase<'a, 'TreeBuilder, '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 | ||||
| [<RequireQualifiedAccess>] | ||||
| module TreeCata = | ||||
|     [<RequireQualifiedAccess>] | ||||
|     type private Instruction = | ||||
|         | Process__TreeBuilder of TreeBuilder | ||||
|         | Process__Tree of Tree | ||||
|     type private Instruction<'a, 'a> = | ||||
|         | Process__TreeBuilder of TreeBuilder<'a> | ||||
|         | Process__Tree of Tree<'a> | ||||
|         | TreeBuilder_Child | ||||
|         | TreeBuilder_Parent | ||||
|         | Tree_Pair of PairOpKind | ||||
|         | Tree_Sequential of int | ||||
|         | Tree_Builder | ||||
|  | ||||
|     let private loop (cata : TreeCata<_, _>) (instructions : ResizeArray<Instruction>) = | ||||
|     let private loop (cata : TreeCata<_, _, _, _>) (instructions : ResizeArray<Instruction<_, _>>) = | ||||
|         let treeStack = ResizeArray () | ||||
|         let treeBuilderStack = ResizeArray () | ||||
|  | ||||
| @@ -120,14 +120,18 @@ module TreeCata = | ||||
|         treeBuilderStack, treeStack | ||||
|  | ||||
|     /// 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 () | ||||
|         instructions.Add (Instruction.Process__TreeBuilder x) | ||||
|         let treeBuilderRetStack, treeRetStack = loop cata instructions | ||||
|         Seq.exactlyOne treeBuilderRetStack | ||||
|  | ||||
|     /// 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 () | ||||
|         instructions.Add (Instruction.Process__Tree x) | ||||
|         let treeBuilderRetStack, treeRetStack = loop cata instructions | ||||
|   | ||||
| @@ -150,112 +150,3 @@ module GiftCata = | ||||
|         instructions.Add (Instruction.Process__Gift x) | ||||
|         let giftRetStack = loop cata instructions | ||||
|         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>] | ||||
| module TestMyList = | ||||
|  | ||||
|     let idCata : MyListCata<_> = | ||||
|     let idCata<'a> : MyListCata<'a, _> = | ||||
|         { | ||||
|             MyList = | ||||
|                 { new MyListCataCase<_> with | ||||
|                 { new MyListCataCase<'a, _> with | ||||
|                     member _.Nil = MyList.Nil | ||||
|  | ||||
|                     member _.Cons head tail = | ||||
| @@ -26,31 +26,28 @@ module TestMyList = | ||||
|  | ||||
|     [<Test>] | ||||
|     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 | ||||
|  | ||||
|     let toListCata = | ||||
|     let toListCata<'a> = | ||||
|         { | ||||
|             MyList = | ||||
|                 { new MyListCataCase<int list> with | ||||
|                 { new MyListCataCase<'a, 'a list> with | ||||
|                     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>] | ||||
|     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 | ||||
|             | MyList.Nil -> [] | ||||
|             | MyList.Cons { | ||||
|                               Head = head | ||||
|                               Tail = tail | ||||
|                           } -> head :: toListNaive tail | ||||
|             | MyList.Cons consCell -> consCell.Head :: toListNaive consCell.Tail | ||||
|  | ||||
|         Check.QuickThrowOnFailure (fun l -> toListNaive l = toListViaCata l) | ||||
|  | ||||
| @@ -62,20 +59,20 @@ module TestMyList = | ||||
|         let sumCata = | ||||
|             { | ||||
|                 MyList = | ||||
|                     { new MyListCataCase<int64> with | ||||
|                     { new MyListCataCase<int, int64> with | ||||
|                         member _.Nil = baseCase | ||||
|                         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 | ||||
|             // but that could have been done naively | ||||
|             (toListViaCata l, baseCase) | ||||
|             ||> 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 | ||||
|   | ||||
| @@ -8,10 +8,10 @@ open ConsumePlugin | ||||
| [<TestFixture>] | ||||
| module TestMyList2 = | ||||
|  | ||||
|     let idCata : MyList2Cata<_> = | ||||
|     let idCata<'a> : MyList2Cata<'a, _> = | ||||
|         { | ||||
|             MyList2 = | ||||
|                 { new MyList2CataCase<_> with | ||||
|                 { new MyList2CataCase<'a, _> with | ||||
|                     member _.Nil = MyList2.Nil | ||||
|  | ||||
|                     member _.Cons head tail = MyList2.Cons (head, tail) | ||||
| @@ -21,6 +21,6 @@ module TestMyList2 = | ||||
|  | ||||
|     [<Test>] | ||||
|     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 | ||||
|   | ||||
| @@ -400,9 +400,28 @@ module internal AstHelper = | ||||
|             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 | ||||
|         | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_, cases, _), _) -> | ||||
|             let cases = | ||||
|                 cases | ||||
|                 |> List.map (fun (SynUnionCase.SynUnionCase (_, ident, kind, _, _, _, _)) -> | ||||
|                     match kind with | ||||
| @@ -420,6 +439,8 @@ module internal AstHelper = | ||||
|                                 ) | ||||
|                         } | ||||
|                 ) | ||||
|  | ||||
|             cases, typars, access | ||||
|         | _ -> failwithf "Failed to get union cases for type that was: %+A" repr | ||||
|  | ||||
|     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 | ||||
|             /// recursive knot of parent types) | ||||
|             Description : FieldDescription | ||||
|             /// Any generic parameters this field consumes | ||||
|             RequiredGenerics : SynType list option | ||||
|         } | ||||
|  | ||||
|     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. | ||||
|     type UnionAnalysis = | ||||
|         { | ||||
|             Accessibility : SynAccess option | ||||
|             Typars : SynTyparDecl list | ||||
|             /// The name of the stack we'll use for the results | ||||
|             /// of returning from a descent into this union type, | ||||
|             /// when performing the cata | ||||
| @@ -112,7 +116,8 @@ module internal CataGenerator = | ||||
|     ///     Seq.exactlyOne {relevantTypar}Stack | ||||
|     let createRunFunction | ||||
|         (cataName : Ident) | ||||
|         (allTypars : SynType list) | ||||
|         (userProvidedTypars : SynTyparDecl list) | ||||
|         (allArtificialTypars : SynType list) | ||||
|         (relevantTypar : SynType) | ||||
|         (unionType : SynTypeDefn) | ||||
|         : SynBinding | ||||
| @@ -121,19 +126,58 @@ module internal CataGenerator = | ||||
|             match unionType with | ||||
|             | SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (longId = id), _, _, _, _, _) -> List.last id | ||||
|  | ||||
|         let allTyparNames = | ||||
|             allTypars | ||||
|         let allArtificialTyparNames = | ||||
|             allArtificialTypars | ||||
|             |> List.map (fun ty -> | ||||
|                 match ty with | ||||
|                 | SynType.Var (SynTypar.SynTypar (ident = ident), _) -> ident | ||||
|                 | _ -> failwith "logic error in generator" | ||||
|             ) | ||||
|  | ||||
|         let userProvidedTypars = | ||||
|             userProvidedTypars | ||||
|             |> List.map (fun (SynTyparDecl.SynTyparDecl (_, ty)) -> SynType.Var (ty, range0)) | ||||
|  | ||||
|         let relevantTyparName = | ||||
|             match relevantTypar with | ||||
|             | SynType.Var (SynTypar.SynTypar (ident = ident), _) -> ident | ||||
|             | _ -> 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 ( | ||||
|             None, | ||||
|             SynBindingKind.Normal, | ||||
| @@ -151,28 +195,7 @@ module internal CataGenerator = | ||||
|             ), | ||||
|             SynPat.CreateLongIdent ( | ||||
|                 SynLongIdent.CreateString ("run" + relevantTypeName.idText), | ||||
|                 [ | ||||
|                     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 ]) | ||||
|                         ) | ||||
|                     ) | ||||
|                 ] | ||||
|                 [ SynPat.CreateParen (cataObject) ; SynPat.CreateParen inputObject ] | ||||
|             ), | ||||
|             Some (SynBindingReturnInfo.Create relevantTypar), | ||||
|             SynExpr.CreateTyped ( | ||||
| @@ -219,8 +242,8 @@ module internal CataGenerator = | ||||
|                                                             Ident.Create (t.idText + "Stack") |> Ident.lowerFirstLetter | ||||
|                                                         ) | ||||
|                                                     ) | ||||
|                                                     allTyparNames, | ||||
|                                                 List.replicate (allTypars.Length - 1) range0, | ||||
|                                                     allArtificialTyparNames, | ||||
|                                                 List.replicate (allArtificialTyparNames.Length - 1) range0, | ||||
|                                                 range0 | ||||
|                                             ), | ||||
|                                         expr = | ||||
| @@ -262,9 +285,10 @@ module internal CataGenerator = | ||||
|         match ty with | ||||
|         | SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (_, _, _, id, _, _, _, _), _, _, _, _, _) -> id | ||||
|  | ||||
|     let getNameUnion (unionType : SynType) : LongIdent option = | ||||
|     let rec getNameUnion (unionType : SynType) : LongIdent option = | ||||
|         match unionType with | ||||
|         | SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) -> Some name | ||||
|         | SynType.App (ty, _, _, _, _, _, _) -> getNameUnion ty | ||||
|         | _ -> None | ||||
|  | ||||
|     let getNameKey (ty : SynTypeDefn) : string = | ||||
| @@ -286,44 +310,8 @@ module internal CataGenerator = | ||||
|         : CataUnionBasicField list | ||||
|         = | ||||
|         let rec go (prefix : string) (name : Ident option) (ty : SynType) : CataUnionBasicField = | ||||
|             let stripped = SynType.stripOptionalParen ty | ||||
|  | ||||
|             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 dealWithPrimitive (typeArgs : SynType list option) (ty : SynType) (typeName : LongIdent) = | ||||
|                 let key = typeName |> List.map _.idText |> String.concat "/" | ||||
|  | ||||
|                 let isKnownUnion = | ||||
|                     allUnionTypes |> List.exists (fun unionTy -> getNameKey unionTy = key) | ||||
| @@ -339,9 +327,28 @@ module internal CataGenerator = | ||||
|                             match name with | ||||
|                             | Some n -> Ident.lowerFirstLetter n | ||||
|                             | None -> Ident.Create $"arg%s{prefix}" | ||||
|                         Description = FieldDescription.Self stripped | ||||
|                         Description = FieldDescription.Self ty | ||||
|                         RequiredGenerics = typeArgs | ||||
|                     } | ||||
|                 else | ||||
|                     { | ||||
|                         FieldName = name | ||||
|                         ArgName = | ||||
|                             match name with | ||||
|                             | Some n -> Ident.lowerFirstLetter n | ||||
|                             | None -> Ident.Create $"arg%s{prefix}" | ||||
|                         Description = FieldDescription.NonRecursive ty | ||||
|                         RequiredGenerics = typeArgs | ||||
|                     } | ||||
|  | ||||
|             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 = | ||||
| @@ -349,10 +356,50 @@ module internal CataGenerator = | ||||
|                                 | 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) | ||||
|  | ||||
|     /// Returns whether this type recursively contains a Self, and the type which | ||||
| @@ -432,7 +479,26 @@ module internal CataGenerator = | ||||
|                 Fields = | ||||
|                     { | ||||
|                         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 | ||||
|             } | ||||
| @@ -461,10 +527,20 @@ module internal CataGenerator = | ||||
|  | ||||
|         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 ( | ||||
|             SynComponentInfo.SynComponentInfo ( | ||||
|                 [ SynAttributeList.Create [ SynAttribute.RequireQualifiedAccess () ] ], | ||||
|                 None, | ||||
|                 typars, | ||||
|                 [], | ||||
|                 [ Ident.Create "Instruction" ], | ||||
|                 PreXmlDoc.Empty, | ||||
| @@ -514,7 +590,7 @@ module internal CataGenerator = | ||||
|             let componentInfo = | ||||
|                 SynComponentInfo.SynComponentInfo ( | ||||
|                     [], | ||||
|                     Some (SynTyparDecls.PostfixList (orderedGenerics, [], range0)), | ||||
|                     Some (SynTyparDecls.PostfixList (analysis.Typars @ orderedGenerics, [], range0)), | ||||
|                     [], | ||||
|                     [ analysis.CataTypeName ], | ||||
|                     // TODO: better docstring | ||||
| @@ -625,30 +701,32 @@ module internal CataGenerator = | ||||
|     /// Build a record which contains one of every cata type. | ||||
|     /// 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}>. | ||||
|     // TODO: this should take an analysis instead | ||||
|     let createCataRecord (cataName : Ident) (doc : PreXmlDoc) (allUnionTypes : SynTypeDefn list) : SynTypeDefn = | ||||
|     let createCataRecord (cataName : Ident) (doc : PreXmlDoc) (analysis : UnionAnalysis list) : SynTypeDefn = | ||||
|         // An artificial generic for each union type | ||||
|         let generics = | ||||
|             allUnionTypes | ||||
|             |> List.map (fun defn -> | ||||
|                 let name = getName defn |> List.map _.idText |> String.concat "" |> Ident.Create | ||||
|                 SynTypar.SynTypar (name, TyparStaticReq.None, false) | ||||
|             ) | ||||
|             analysis | ||||
|             |> List.map (fun analysis -> SynTypar.SynTypar (analysis.GenericName, TyparStaticReq.None, false)) | ||||
|  | ||||
|         // A field for each cata | ||||
|         let fields = | ||||
|             allUnionTypes | ||||
|             |> List.map (fun unionType -> | ||||
|                 let nameForDoc = List.last (getName unionType) |> _.idText | ||||
|             analysis | ||||
|             |> List.map (fun analysis -> | ||||
|                 let nameForDoc = List.last(analysis.ParentTypeName).idText | ||||
|  | ||||
|                 let doc = | ||||
|                     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 = | ||||
|                     SynType.App ( | ||||
|                         SynType.CreateLongIdent (SynLongIdent.CreateString (List.last(name).idText + "CataCase")), | ||||
|                         SynType.LongIdent (SynLongIdent.CreateFromLongIdent [ analysis.CataTypeName ]), | ||||
|                         Some range0, | ||||
|                         generics |> List.map (fun v -> SynType.Var (v, range0)), | ||||
|                         userInputGenerics @ artificialGenerics, | ||||
|                         List.replicate (generics.Length - 1) range0, | ||||
|                         Some range0, | ||||
|                         false, | ||||
| @@ -658,7 +736,7 @@ module internal CataGenerator = | ||||
|                 SynField.SynField ( | ||||
|                     [], | ||||
|                     false, | ||||
|                     Some (List.last name), | ||||
|                     Some (List.last analysis.ParentTypeName), | ||||
|                     ty, | ||||
|                     false, | ||||
|                     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 = | ||||
|             SynComponentInfo.SynComponentInfo ( | ||||
|                 [], | ||||
|                 Some ( | ||||
|                     SynTyparDecls.PostfixList ( | ||||
|                         generics |> List.map (fun ty -> SynTyparDecl.SynTyparDecl ([], ty)), | ||||
|                         [], | ||||
|                         range0 | ||||
|                     ) | ||||
|                 ), | ||||
|                 Some (SynTyparDecls.PostfixList (genericsFromUserInput @ genericsFromCata, [], range0)), | ||||
|                 [], | ||||
|                 [ cataName ], | ||||
|                 doc, | ||||
| @@ -714,13 +797,20 @@ module internal CataGenerator = | ||||
|  | ||||
|         allUnionTypes | ||||
|         |> List.map (fun unionType -> | ||||
|             let cases, typars, access = AstHelper.getUnionCases unionType | ||||
|  | ||||
|             let cases = | ||||
|                 AstHelper.getUnionCases unionType | ||||
|                 cases | ||||
|                 |> List.map (fun prod -> | ||||
|                     let fields = | ||||
|                         prod.Fields | ||||
|                         |> List.indexed | ||||
|                         |> List.collect (fun (i, node) -> | ||||
|                             let availableGenerics = | ||||
|                                 match node.Type with | ||||
|                                 | SynType.App (_, _, vars, _, _, _, _) -> vars | ||||
|                                 | _ -> [] | ||||
|  | ||||
|                             match getNameUnion node.Type with | ||||
|                             | None -> | ||||
|                                 analyse allRecordTypes allUnionTypes i [ node ] |> List.map CataUnionField.Basic | ||||
| @@ -742,6 +832,8 @@ module internal CataGenerator = | ||||
|             let unionTypeName = getName unionType | ||||
|  | ||||
|             { | ||||
|                 Typars = typars | ||||
|                 Accessibility = access | ||||
|                 StackName = | ||||
|                     List.last(getName unionType).idText + "Stack" | ||||
|                     |> Ident.Create | ||||
| @@ -1218,6 +1310,23 @@ module internal CataGenerator = | ||||
|                 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 = | ||||
|             SynPat.LongIdent ( | ||||
|                 SynLongIdent.CreateString "loop", | ||||
| @@ -1231,8 +1340,8 @@ module internal CataGenerator = | ||||
|                                 SynType.App ( | ||||
|                                     SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataTypeName ]), | ||||
|                                     Some range0, | ||||
|                                     List.replicate analysis.Length (SynType.Anon range0), | ||||
|                                     List.replicate (analysis.Length - 1) range0, | ||||
|                                     List.replicate genericCount (SynType.Anon range0), | ||||
|                                     List.replicate (genericCount - 1) range0, | ||||
|                                     Some range0, | ||||
|                                     false, | ||||
|                                     range0 | ||||
| @@ -1245,7 +1354,7 @@ module internal CataGenerator = | ||||
|                                 SynType.App ( | ||||
|                                     SynType.CreateLongIdent "ResizeArray", | ||||
|                                     Some range0, | ||||
|                                     [ SynType.CreateLongIdent "Instruction" ], | ||||
|                                     [ instructionsArrType ], | ||||
|                                     [], | ||||
|                                     Some range0, | ||||
|                                     false, | ||||
| @@ -1404,6 +1513,9 @@ module internal CataGenerator = | ||||
|                 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 = | ||||
|             allUnionTypes | ||||
|             |> List.map (fun unionType -> | ||||
| @@ -1414,12 +1526,14 @@ module internal CataGenerator = | ||||
|                 |> fun x -> SynType.Var (x, range0) | ||||
|             ) | ||||
|  | ||||
|         let userProvidedGenerics = analysis |> List.collect (fun x -> x.Typars) | ||||
|  | ||||
|         let runFunctions = | ||||
|             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 = | ||||
|             createCataStructure analysis | ||||
| @@ -1432,7 +1546,7 @@ module internal CataGenerator = | ||||
|                 $" Specifies how to perform a fold (catamorphism) over the type %s{parentName} and its friends." | ||||
|  | ||||
|         let cataRecord = | ||||
|             SynModuleDecl.Types ([ createCataRecord cataName recordDoc allUnionTypes ], range0) | ||||
|             SynModuleDecl.Types ([ createCataRecord cataName recordDoc analysis ], range0) | ||||
|  | ||||
|         SynModuleOrNamespace.CreateNamespace ( | ||||
|             ns, | ||||
| @@ -1453,14 +1567,7 @@ module internal CataGenerator = | ||||
|                 ] | ||||
|         ) | ||||
|  | ||||
| /// Myriad generator that provides a catamorphism for an algebraic data type. | ||||
| [<MyriadGenerator("create-catamorphism")>] | ||||
| type CreateCatamorphismGenerator () = | ||||
|  | ||||
|     interface IMyriadGenerator with | ||||
|         member _.ValidInputExtensions = [ ".fs" ] | ||||
|  | ||||
|         member _.Generate (context : GeneratorContext) = | ||||
|     let generate (context : GeneratorContext) : Output = | ||||
|         let ast, _ = | ||||
|             Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head | ||||
|  | ||||
| @@ -1504,8 +1611,15 @@ type CreateCatamorphismGenerator () = | ||||
|  | ||||
|         let modules = | ||||
|             namespaceAndTypes | ||||
|                 |> List.map (fun (ns, taggedType, unions, records) -> | ||||
|                     CataGenerator.createModule opens ns taggedType unions records | ||||
|                 ) | ||||
|             |> 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. | ||||
| [<MyriadGenerator("create-catamorphism")>] | ||||
| type CreateCatamorphismGenerator () = | ||||
|  | ||||
|     interface IMyriadGenerator with | ||||
|         member _.ValidInputExtensions = [ ".fs" ] | ||||
|  | ||||
|         member _.Generate (context : GeneratorContext) = CataGenerator.generate context | ||||
|   | ||||
		Reference in New Issue
	
	Block a user