[Haskell]
От: Алексей Мартынов Россия  
Дата: 13.03.07 13:49
Оценка:
Есть задача — расчетная программа на 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'а для меня, если возможно, то простые примеры или ссылки на них.

Алексей Мартынов.
Алексей Мартынов
Re: [Haskell]
От: deniok Россия  
Дата: 13.03.07 14:00
Оценка:
Здравствуйте, Алексей Мартынов, Вы писали:

АМ>Есть задача — расчетная программа на Haskell, которая параметры расчета должна получать из из файла следующего вида:

АМ>
АМ>a=15
АМ>b=10
АМ>c=1 4 5.1

АМ>


Непонятно — параметров там может быть и больше? c, d, e, ... , x, y, ... ?
И они никак не типизируются? 1 4 5.1 — это тройка чисел?
Re[2]: [Haskell]
От: deniok Россия  
Дата: 13.03.07 14:30
Оценка:
Здравствуйте, 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.
Re[3]: [Haskell]
От: Алексей Мартынов Россия  
Дата: 13.03.07 15:24
Оценка:
Здравствуйте, 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>data Parameter = Parameter Char String -- a=15 сохраним как Parameter 'a' "15"
D>

D>Ну а вместо Parameters использовал бы список из Parameter.

И функция поиска в списке? Для случая нефиксированных параметров — идеально подходит. Мне кажется, что это будет очень развесисто для фиксированного набора.

Спасибо за идею, изучать Haskell после значительного опыта с С++, мягко говоря, трудно

Алексей Мартынов
Алексей Мартынов
Re[4]: [Haskell]
От: deniok Россия  
Дата: 13.03.07 17:24
Оценка: 2 (1)
Здравствуйте, Алексей Мартынов, Вы писали:

АМ>Вообще говоря, список фиксированный полностью фиксированный, но для удобства пользователей не хочется фиксировать порядок в файле. Случай с "c" особый, его обрабатывать буду после, так как там будет список значений для итеративного расчета с использованием остальный параметров — их штук 5 и всех надо заправить аргументами в конкретные вычислительную функцию, evaluate это только обертка.


Ну если файл набивается пользователем, то тогда уж стоит предусмотреть и такое "a_ =_ 1" (с пробелами). Можно использовать Parsec, чтобы разобрать ввод (или просто пройтись lex'ом), а потом вызвать
evaluate :: Double->Double->[Double]->ResultTypeYouNeed -- a, b, c как список

не замешивая в evaluate никакого IO (нужен ли он там?).
Re[5]: [Haskell]
От: Алексей Мартынов Россия  
Дата: 14.03.07 07:58
Оценка:
Здравствуйте, 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, буду копать дальше.

Алексей Мартынов
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Алексей Мартынов
Re[6]: [Haskell]
От: palm mute  
Дата: 14.03.07 12:25
Оценка: 1 (1)
Здравствуйте, Алексей Мартынов, Вы писали:


АМ>Спасибо за подсказку насчеть Parsec, буду копать дальше.


Для такого воробья Parsec — слишком мощная пушка. Немного многословно, но не придется разбираться с Парсеком:

parseNameVal :: (Read a) => String -> (String, a)
parseNameVal s = case [ (name, val) | (name, tail)  <- lex s, 
                                      ("=", tail' ) <- lex tail,
                                      (val, tail'') <- reads tail',
                                      ("", "") <- lex tail'' ] of
                   [result] -> result
                   _        -> error "Cannot parse"


Обработка ошибок упрощена специально, чтобы не запутать. Вариантов много, даже слишком: http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors.
Re[7]: [Haskell]
От: deniok Россия  
Дата: 14.03.07 12:49
Оценка:
Здравствуйте, palm mute, Вы писали:

PM>Здравствуйте, Алексей Мартынов, Вы писали:



АМ>>Спасибо за подсказку насчеть Parsec, буду копать дальше.


PM>Для такого воробья Parsec — слишком мощная пушка. Немного многословно, но не придется разбираться с Парсеком:


Поскипал.

200% ИМХО:
По-моему, всё-таки, разобраться с Parsec проще, чем с этими зацеплеными генераторами в list comprehensions (если, конечно, до этого имел представление о парсинге). Здесь мы, фактически, монтируем парсер с нуля языковыми средствами, что, слава Хаскеллу, не требует много кода, но тем не менее... А в Parsec масса всего готовенького — бери и пользуйся.
Re[8]: [Haskell]
От: palm mute  
Дата: 14.03.07 13:12
Оценка: +1
Здравствуйте, deniok, Вы писали:

D>По-моему, всё-таки, разобраться с Parsec проще, чем с этими зацеплеными генераторами в list comprehensions (если, конечно, до этого имел представление о парсинге). Здесь мы, фактически, монтируем парсер с нуля языковыми средствами, что, слава Хаскеллу, не требует много кода, но тем не менее... А в Parsec масса всего готовенького — бери и пользуйся.


Дело в том, что я даже не предлагаю с этими генераторамим разбираться. Я предлагаю взять и воспользоваться гшотовой функцией, чтобы покончить с второстепенной задачей парсинга конфигов и перейти к расчетам. Я сам многократно попадался в ловушку Yak Shaving, потому представляю, во что может вылиться изучение Парсека, чтение статей о monadic parser combinators, попытки разобраться с монадами, среди которых не последнее место занимает Cont , и т.д. В результате у человека будет опухшая голова и нерешенная элементарная задача. Учиться надо постепенно и с практикой.
Re[9]: [Haskell]
От: deniok Россия  
Дата: 14.03.07 14:59
Оценка: +1
Здравствуйте, palm mute, Вы писали:

Упаси боже заставлять человека разбираться как устроен Parsec (если у него нет времени/желания/необходимости). Я лишь о том, что им пользоваться просто: есть стандартные парсеры, комбинируешь их прозрачным образом — получаешь более сложные.
Re: [Haskell]
От: Трурль  
Дата: 15.03.07 07:18
Оценка: 9 (2)
Здравствуйте, Алексей Мартынов, Вы писали:
АМ>Выглядит все довольно монструозненько

имхо, проще всего
tipa_parse :: String -> [(String,String)]  
tipa_parse = (map parse_line).lines where
             parse_line s = (a,tail b) where (a,b)= break('='==) s
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.