well, you can:

  1. switch to immutable data structures and build project incrementally
  2. use discrimiated union for defining duration
  3. add some auxiliary types for dummy arguments to make dsl more robust

with these changes your sample can be rewritten into something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
open System

type Task = {
    Name : string
    Duration : string 
    }

type Resource = {
    Name : string
    Position : string
    Rate : int
    }

type Group = {
    Name : string
    Person : Resource
    Tasks : Task list
    }

type Project = {
    Name : string
    Resources : Resource list
    StartDate : DateTime
    Groups : Group list
    }

type StartsWith = | Literal
type IsA = | Literal 
type Takes = | Literal
type WithRate = | Literal
type DoneBy = | Literal

type Duration = Hour | Day | Week | Month

let starts = StartsWith.Literal
let isa = IsA.Literal
let takes = Takes.Literal
let with_rate = WithRate.Literal
let done_by = DoneBy.Literal

let project name (_ : StartsWith) startDate = { 
        Name = name 
        Resources = []
        Groups = []
        StartDate = DateTime.Parse(startDate) 
    }

let resource name (_ : IsA) position (_ : WithRate) rate (p : Project) = 
    let resource = {Name = name; Position = position; Rate = rate}
    { p with Resources = resource::p.Resources }

let group name (_ : DoneBy) resourceName tasks (project : Project) = 
    let person = project.Resources |> List.find (fun r -> r.Name = resourceName)
    let group = {Name = name; Person = person; Tasks = tasks}
    { project with Groups = group::project.Groups }

let task name (_ : Takes) count duration =
    let durationText = 
        match duration with
        | Hour -> sprintf "%dh" count 
        | Day -> sprintf "%dd" count 
        | Week -> sprintf "%dwk" count 
        | Month -> sprintf "%dmon" count 
    {Name = name; Duration = durationText}

let myProject = 
    project "F# DSL Article" starts "01/01/2009"
    |> resource "Dmitri" isa "Writer" with_rate 140
    |> resource "Computer" isa "Dumb Machine" with_rate 0

    |> group "DSL Popularization" done_by "Dmitri" [
        task "Create basic estimation DSL" takes 1 Day
        task "Write article" takes 1 Day
        task "Post on CP and wait for comments" takes 1 Week
    ]

    |> group "Infrastructure Support" done_by "Computer" [
        task "Provide VS2010 and MS Project" takes 1 Day
        task "Download and deploy TypograFix" takes 1 Day
        task "Sit idly while owner waits for comments" takes 1 Week
    ]

printfn "%A" myProject
By on 9/9/2010 2:10 AM ()

Well, almost like I want it to be, but the DSL now contains a lot of "garbage" like those "|>" and "[]"... Previous syntax was much more clear for "dummies"

By on 9/9/2010 11:21 AM ()

looks like your original syntax relies on the order and mutability to link objects created later back to things created earlier.

You may be able to make the |>, [] being implicit using computation expression along the line of:

project_def {

}

and play around the .Combine(...) builder member function

By on 9/9/2010 8:06 PM ()

I'm total noob at F# :) Going to learn computation expressions :)

By on 9/9/2010 11:35 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper