Created
June 18, 2009 20:15
-
-
Save dgfitch/132165 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Crap = | |
| Composite of Crap list | |
/// Name, a list of attributes, and it's sub-item[s] | |
| Element of string * Attribute list * Crap | |
| Content of string | |
and Attribute = string * string | |
let d = | |
[ | |
Element ("header", [("Top Margin", "3in")], Content "WOO") | |
Element ("para", [("Ref", "1")], Content "1. Awesome") | |
Element ("para", [("Ref", "2")], Content "2. Bar") | |
Element ("nested", [], | |
Composite [ | |
Content "text" | |
Element ("nested", [], Content "Deep!") | |
] | |
) | |
] | |
/// Insert `item` into `list` after the first item where `f` is true, or stick it at the end | |
// (I'm sure there are a million better ways to do this) | |
let InsertAfter f list item = | |
let rec insert f (list1:'a list) (list2:'a list) (item:'a) = | |
if f list2.Head then | |
list1 @ list2.Head :: item :: list2.Tail | |
else | |
if list2.Length = 1 then | |
list1 @ list2 @ [item] | |
else | |
insert f (list1 @ [list2.Head]) list2.Tail item | |
if list = [] then | |
item::[] | |
else | |
insert f [] list item | |
// So, insert into a Crap list after a certain function or pattern is true | |
let d_head = | |
InsertAfter | |
(function Element("header",_,_) -> true | _ -> false) | |
d (Content "3. YAY") | |
let d_ref = | |
InsertAfter | |
(function Element("para",a,_) | |
when a |> List.exists | |
(function ("Ref", "2") -> true | _ -> false) | |
-> true | _ -> false) | |
d (Content "3. YAY") | |
// This is great and everything except can you see all those "| _ -> false" sticking out? | |
// There's got to be a more concise representation. | |
// Now I'll imagine that I want to pass an active pattern around. | |
// Except I'm kind of not smart enough to figure it out, exactly. | |
// For one, I'm not sure what the type of pattern should be. (Crap -> bool)? (Crap -> Crap option)? | |
// And for another, I'm not sure how to apply the pattern that's stored in the value passed in. | |
let InsertAfter' pattern list item = | |
let rec insert pattern (list1:'a list) (list2:'a list) (item:'a) = | |
match list2.Head with | |
| pattern -> list1 @ list2.Head :: item :: list2.Tail | |
| _ -> | |
if list2.Length = 1 then | |
list1 @ list2 @ [item] | |
else | |
insert pattern (list1 @ [list2.Head]) list2.Tail item | |
if list = [] then | |
item::[] | |
else | |
insert pattern [] list item | |
let (|NameIs|_|) s c = | |
match c with | |
| Element(name,_,_) as e when name.Contains s -> Some e | |
| _ -> None | |
let d_head_CompleteFail = | |
InsertAfter' | |
NameIs "header" | |
d (Content "3. YAY") | |
// But this isn't necessarily more concise than the inline patterns, either |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment