Previous Entry Add to Memories Share Next Entry
Создание DSL на языке Haskell
eye
[info]voidex
По мотивам поста на Хабрахабре от скуки написал такую же штуку на Haskell'е. Просто, чтобы сравнить.
Я, правда, самой главной функции не написал, но подозреваю, что она на .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

Tags:

А где этот DSL проверяет, что нельзя написать как-то так:

resource "Dmitri" starts "Writer" done_by 140



ну это же как два пальца добавить

На Фшарпе посимпатичнее будет. :)
Занятное упражнение, но как-то меня стремают идеи ДСЛей в мэйнстриме. Один чётко определённый диалект языка куда полезнее.

Это дело, конечно, субъективное, но ДСл вроде одинаковый, accessor'ы могут быть сгенерированы, т.е. на фшарпе симпатичнее 4 функции project/resource/group/task? Там они, имхо, понятнее для большинства просто.

Да, я именно про внешний вид программ (для меня и фшарп, и хаскель - один фик китайский :) ).
А сам я на Цэ-шарпе пишу.

Ну тогда понятно. На F# расписано более императивно. Тут тоже можно каждую функцию на 5 понятных (понятных всем, мне-то и эти понятны) строк развернуть.
Золотую середину без обратной связи найти сложно, раньше мне такие в-одну-строку-с-кучей-операторов тяжело давались, а теперь наоборот проще, не надо в голове прокручивать.

В том и особенность промышленного программинга - должно быть понятно всем и не только на примере фибоначей. :) Можно только позавидовать академическим кругам, где каждый сам себе супермозг. :)

Должно быть понятно всем программистам, владеющим этим ЯП, а не всем вообще.
Бессмысленно писать на Хаскеле так, чтобы понял программист на чистом Си, и наоборот, собственно тоже, просто Хаскель редко бывает первым языком, и программисты на нем знают, как правило, несколько других, вот и все.

Да уж, ничем не лучше брейнфака.Если в код в пару тысяч строк на хаскеле вникать , то можно повесится. Программиста пишущего на хаскеле наверное хрен уволят иначе новый прогер, хрен, что разберёт.

Вникал в чужие коды, могу сказать, что новый прогер на хаскеле (а как иначе?) разберется без особых проблем.
Функциональная чистота очень помогает, я теперь от методов классов и любых функций с состояниями плююсь, фиг проследишь, где кто кого куда.
В том же примере на F# на пустом месте глобальная переменная. Она, конечно, тут не шибко мешает, но уже нельзя создать список проектов и prepare их в алфавитном порядке, например.

Вообще одно и то же можно записать несколькими тупыми строками, но тогда при чтении придется прокручивать их в голове, а можно одной и сложной, но тогда придется понимать, что там к чему.
Идеально, я считаю, писать так, чтобы читая только названия идентификаторов, можно было понять, о чём речь примерно.
Например, в функции task читается так (в обратную сторону): добавить таск в (Task ... :) - таски (tasks) - в голове (headA) - групп (groups).
Вот функция group мне и самому не очень нравится.

Красиво.

(Anonymous)

2011-12-29 11:16 am (UTC)

Тут красиво, а на F# левость. Вообще Haskell проще учится и позволяет в дальнейшем писать более красивый код на Python. :)

You are viewing [info]voidex's journal