Есть задача — расчетная программа на Haskell, которая параметры расчета должна получать из из файла следующего вида:
a=15
b=10
c=1 4 5.1
Как это наиболее понятно реализовать? Лучшее, что получилось — некий тип (String только для простоты примера):
data Parameters = Parameters (Maybe String) (Maybe String)
data ParameterName = ParamA
| ParamB
в паре с функцией, которая принимает его аргументом и, по мере чтения параметров, рекурсивно вызывает себя с обновленными данными. При достижении конца параметров запускается вычисление. Что-то в стиле:
readParameters p = do str <- getLine
case str of
('a':'=':xs) -> readParameters (setParameter p ParamA xs)
('b':'=':xs) -> readParameters (setParameter p ParamB xs)
"" -> evaluate p
-- Используется для изменения соответствующего параметра
setParameter :: Parameters -> ParameterName -> String -> Parameters
evaluate :: Parameters -> IO ()
Выглядит все довольно монструозненько
А посему хотелось бы получить советы как это лучше сделать, и, по причине новизны Haskell'а для меня, если возможно, то простые примеры или ссылки на них.
Здравствуйте, Алексей Мартынов, Вы писали:
АМ>Есть задача — расчетная программа на Haskell, которая параметры расчета должна получать из из файла следующего вида: АМ>
АМ>a=15
АМ>b=10
АМ>c=1 4 5.1
АМ>
Непонятно — параметров там может быть и больше? c, d, e, ... , x, y, ... ?
И они никак не типизируются? 1 4 5.1 — это тройка чисел?
Здравствуйте, deniok, Вы писали:
D>Здравствуйте, Алексей Мартынов, Вы писали:
АМ>>Есть задача — расчетная программа на Haskell, которая параметры расчета должна получать из из файла следующего вида: АМ>>
АМ>>a=15
АМ>>b=10
АМ>>c=1 4 5.1
АМ>>
D>Непонятно — параметров там может быть и больше? c, d, e, ... , x, y, ... ? D>И они никак не типизируются? 1 4 5.1 — это тройка чисел?
Просто ответ зависит от того что требуется
Когда вызывается
evaluate :: Parameters -> IO ()
какие требования накладываются на число и тип параметров? Одно дело? если просто фиксированное число чисел, а другое если там неизвестного размера список (или ещё хуже дерево) объектов сложной природы. Если, скажем, надо хранить имя параметра, то я бы сделал так
data Parameter = Parameter Char String-- a=15 сохраним как Parameter 'a' "15"
Ну а вместо Parameters использовал бы список из Parameter.
Здравствуйте, deniok, Вы писали:
АМ>>>Есть задача — расчетная программа на Haskell, которая параметры расчета должна получать из из файла следующего вида: АМ>>>
АМ>>>a=15
АМ>>>b=10
АМ>>>c=1 4 5.1
АМ>>>
D>>Непонятно — параметров там может быть и больше? c, d, e, ... , x, y, ... ? D>>И они никак не типизируются? 1 4 5.1 — это тройка чисел?
Вообще говоря, список фиксированный полностью фиксированный, но для удобства пользователей не хочется фиксировать порядок в файле. Случай с "c" особый, его обрабатывать буду после, так как там будет список значений для итеративного расчета с использованием остальный параметров — их штук 5 и всех надо заправить аргументами в конкретные вычислительную функцию, evaluate это только обертка.
D>Когда вызывается D>
D>evaluate :: Parameters -> IO ()
D>
D>какие требования накладываются на число и тип параметров? Одно дело? если просто фиксированное число чисел, а другое если там неизвестного размера список (или ещё хуже дерево) объектов сложной природы. Если, скажем, надо хранить имя параметра, то я бы сделал так D>
D>Ну а вместо Parameters использовал бы список из Parameter.
И функция поиска в списке? Для случая нефиксированных параметров — идеально подходит. Мне кажется, что это будет очень развесисто для фиксированного набора.
Спасибо за идею, изучать Haskell после значительного опыта с С++, мягко говоря, трудно
Здравствуйте, Алексей Мартынов, Вы писали:
АМ>Вообще говоря, список фиксированный полностью фиксированный, но для удобства пользователей не хочется фиксировать порядок в файле. Случай с "c" особый, его обрабатывать буду после, так как там будет список значений для итеративного расчета с использованием остальный параметров — их штук 5 и всех надо заправить аргументами в конкретные вычислительную функцию, evaluate это только обертка.
Ну если файл набивается пользователем, то тогда уж стоит предусмотреть и такое "a_ =_ 1" (с пробелами). Можно использовать Parsec, чтобы разобрать ввод (или просто пройтись lex'ом), а потом вызвать
evaluate :: Double->Double->[Double]->ResultTypeYouNeed -- a, b, c как список
не замешивая в evaluate никакого IO (нужен ли он там?).
Здравствуйте, deniok, Вы писали:
АМ>>Вообще говоря, список фиксированный полностью фиксированный, но для удобства пользователей не хочется фиксировать порядок в файле. Случай с "c" особый, его обрабатывать буду после, так как там будет список значений для итеративного расчета с использованием остальный параметров — их штук 5 и всех надо заправить аргументами в конкретные вычислительную функцию, evaluate это только обертка.
D>Ну если файл набивается пользователем, то тогда уж стоит предусмотреть и такое "a_ =_ 1" (с пробелами). Можно использовать Parsec, чтобы разобрать ввод (или просто пройтись lex'ом), а потом вызвать D>
D>evaluate :: Double->Double->[Double]->ResultTypeYouNeed -- a, b, c как список
D>
D>не замешивая в evaluate никакого IO (нужен ли он там?).
Я думал об этом, но это задача следующего этапа — примерно как индейца майя отправить на Луну Мне сначала надо сделать "чтобы работало", потом буду улучшать. В абсолютно новом мире трудновато
Да и IO, как я вчера прикинул, там не нужен — надо вернуть результат расчета, который другими средствами вывести куда-либо.
Спасибо за подсказку насчеть Parsec, буду копать дальше.
Здравствуйте, palm mute, Вы писали:
PM>Здравствуйте, Алексей Мартынов, Вы писали:
АМ>>Спасибо за подсказку насчеть Parsec, буду копать дальше.
PM>Для такого воробья Parsec — слишком мощная пушка. Немного многословно, но не придется разбираться с Парсеком:
Поскипал.
200% ИМХО:
По-моему, всё-таки, разобраться с Parsec проще, чем с этими зацеплеными генераторами в list comprehensions (если, конечно, до этого имел представление о парсинге). Здесь мы, фактически, монтируем парсер с нуля языковыми средствами, что, слава Хаскеллу, не требует много кода, но тем не менее... А в Parsec масса всего готовенького — бери и пользуйся.
Здравствуйте, deniok, Вы писали:
D>По-моему, всё-таки, разобраться с Parsec проще, чем с этими зацеплеными генераторами в list comprehensions (если, конечно, до этого имел представление о парсинге). Здесь мы, фактически, монтируем парсер с нуля языковыми средствами, что, слава Хаскеллу, не требует много кода, но тем не менее... А в Parsec масса всего готовенького — бери и пользуйся.
Дело в том, что я даже не предлагаю с этими генераторамим разбираться. Я предлагаю взять и воспользоваться гшотовой функцией, чтобы покончить с второстепенной задачей парсинга конфигов и перейти к расчетам. Я сам многократно попадался в ловушку Yak Shaving, потому представляю, во что может вылиться изучение Парсека, чтение статей о monadic parser combinators, попытки разобраться с монадами, среди которых не последнее место занимает Cont , и т.д. В результате у человека будет опухшая голова и нерешенная элементарная задача. Учиться надо постепенно и с практикой.
Упаси боже заставлять человека разбираться как устроен Parsec (если у него нет времени/желания/необходимости). Я лишь о том, что им пользоваться просто: есть стандартные парсеры, комбинируешь их прозрачным образом — получаешь более сложные.