Skip to content

Instantly share code, notes, and snippets.

@dgfitch
Created June 18, 2009 20:15
Show Gist options
  • Save dgfitch/132165 to your computer and use it in GitHub Desktop.
Save dgfitch/132165 to your computer and use it in GitHub Desktop.
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