Я, правда, самой главной функции не написал, но подозреваю, что она на .Net завязана (если даже не на код автора), а разбираться мне было лень, да и суть статьи была в DSL.
data Project = Project String [Resource] UTCTime [Group] deriving (Read, Show)
data Resource = Resource String String Int deriving (Read, Show)
data Group = Group String Resource [Task] deriving (Read, Show)
data Task = Task String String deriving (Read, Show)
resources = accessor (\(Project _ r _ _) -> r) (\r (Project s _ t g) -> Project s r t g)
groups = accessor (\(Project _ _ _ g) -> g) (\g (Project s r t _) -> Project s r t g)
tasks = accessor (\(Group _ _ t) -> t) (\t (Group s r _) -> Group s r t)
headA = accessor head (\v -> (v:).tail)
resourceName (Resource name _ _) = name
project name _ start = put (Project name [] (getTime start) [])
resource name _ position _ rate = modify $ resources ^: (Resource name position rate :)
group name _ resource = modify $ \r -> (groups ^: (Group name (res r) [] :)) r where
res r = fromMaybe (error $ "Group \"" ++ name ++ "\": no resource with name \"" ++ resource ++ "\" found!") $
find ((resource == ) . resourceName) (r ^. resources)
task name _ count time = modify $ groups ^: headA ^: tasks ^: (Task name format :) where
format = show count ++ case time of
Hour -> "h"
Day -> "d"
Week -> "wk"
Month -> "mon"
-- time
getTime =
(uncurry mplus) . (parseWith "%d/%m/%Y" &&& parseWith "%d/%m/%y") >>>
fromMaybe (error "Invalid time format") where
parseWith = parseTime defaultTimeLocale
-- keywords
starts = ()
isa = ()
rate = ()
done_by = ()
takes = ()
-- duration
data Duration = Hour | Day | Week | Month
hours = Hour
hour = Hour
days = Day
day = Day
weeks = Week
week = Week
months = Month
month = Month
makeProject = flip execState (Project "" [] (error "Time not set") [])
test = makeProject $ do
project "F# DSL Article" starts "01/01/2009"
resource "Dmitri" isa "Writer" rate 140
resource "Computer" isa "Dumb Machine" rate 0
group "DSL Popularization" done_by "Dmitri"
task "Create basic estimation DSL" takes 1 day
task "Write article" takes 1 day
task "Post article 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
2009-08-30 10:36 am (UTC)
2009-08-30 11:55 am (UTC)
2009-09-01 08:54 am (UTC)
Занятное упражнение, но как-то меня стремают идеи ДСЛей в мэйнстриме. Один чётко определённый диалект языка куда полезнее.
2009-09-01 02:33 pm (UTC)
2009-09-01 03:05 pm (UTC)
А сам я на Цэ-шарпе пишу.
2009-09-01 09:04 pm (UTC)
Золотую середину без обратной связи найти сложно, раньше мне такие в-одну-строку-с-кучей-операторов тяжело давались, а теперь наоборот проще, не надо в голове прокручивать.
2009-09-02 10:12 am (UTC)
2009-09-02 12:57 pm (UTC)
Бессмысленно писать на Хаскеле так, чтобы понял программист на чистом Си, и наоборот, собственно тоже, просто Хаскель редко бывает первым языком, и программисты на нем знают, как правило, несколько других, вот и все.
2009-09-01 07:01 pm (UTC)
2009-09-01 09:12 pm (UTC)
Функциональная чистота очень помогает, я теперь от методов классов и любых функций с состояниями плююсь, фиг проследишь, где кто кого куда.
В том же примере на F# на пустом месте глобальная переменная. Она, конечно, тут не шибко мешает, но уже нельзя создать список проектов и prepare их в алфавитном порядке, например.
Вообще одно и то же можно записать несколькими тупыми строками, но тогда при чтении придется прокручивать их в голове, а можно одной и сложной, но тогда придется понимать, что там к чему.
Идеально, я считаю, писать так, чтобы читая только названия идентификаторов, можно было понять, о чём речь примерно.
Например, в функции
taskчитается так (в обратную сторону): добавить таск в(Task ... :)- таски(tasks)- в голове(headA)- групп(groups).Вот функция
groupмне и самому не очень нравится.Красиво.
(Anonymous)
2011-12-29 11:16 am (UTC)