Поясните пару моментов, которые хоть и решил, но все равно остались не понятны
Была ошибка, связанная с тем что обработчик Nothing и Just v должны возвращать один тип:
из — за этого пришлось писать дополнительную функцию update, т.к. H.update возвращает IO Bool,
как можно короче написать этот код? И автоматически следует следующий вопрос, если обработчики case возвращают значения, то
как их можно получить? Правильно ли написал функцию fill? происходит ее замыкание (вроде правильно сказал)?
И у меня не получилось записать putStr $ show $ H.toList m , как можно это дело записать в одну строчку?
И интересует как этот код можно улучшить и в чем оверхед
import System.IO
import qualified Data.HashTable as H
fillMark :: H.HashTable String [String] -> [String] -> IO ()
fillMark m (f1:f2) = fill f1 f2
where fill :: String -> [String] -> IO ()
fill _ [] = return ()
fill pref (suf:zs) =
do find <- H.lookup m pref
case find of
Nothing -> H.insert m pref [suf]
Just v -> update pref (v ++ [suf])
where update :: String -> [String] -> IO ()
update key val = do H.update m key val
return ()
fill suf zs
main :: IO ()
main = do
s <- readFile "c:\\test.hs"
m <- H.new (==) H.hashString
fillMark m (words s)
l <- H.toList m
putStr $ show l
Здравствуйте, Аноним, Вы писали:
А>Поясните пару моментов, которые хоть и решил, но все равно остались не понятны А>Была ошибка, связанная с тем что обработчик Nothing и Just v должны возвращать один тип: А>из — за этого пришлось писать дополнительную функцию update, т.к. H.update возвращает IO Bool, А>как можно короче написать этот код? И автоматически следует следующий вопрос, если обработчики case возвращают значения, то А>как их можно получить? Правильно ли написал функцию fill? происходит ее замыкание (вроде правильно сказал)? А>И у меня не получилось записать putStr $ show $ H.toList m , как можно это дело записать в одну строчку? А>И интересует как этот код можно улучшить и в чем оверхед
1. Разделяй IO и чистые функции.
2. Используй Data.Map — вопросы как улучишить отпадут сами собой — pattern matching, pattern guards (для lookup) сильно помогут писать декларативный код.
3. Если уж используешь монады — используй их:
Здравствуйте, Аноним, Вы писали:
А>И интересует как этот код можно улучшить и в чем оверхед
Я так понял задача заключается в том, чтобы построить пары (слово X, список слов которые следуют в тексте за X).
Задача решается в одну-две строчки. Как уже сказал lomeo легче использовать Data.Map
1. С помощью zip строим список пар (слово, слово следующее за ним)
2. Обрабатываем эти пары с помощью Data.Map.insertWith
Если хочется оставаться с HashTable, нужно просто сделать аналог insertWith для HashTable.
Здравствуйте, Буравчик, Вы писали: Б>P.S. Напиши, что получилось...
Получилось следующее
import qualified Data.Map as M
fillMark' :: String -> M.Map String [String]
fillMark' text = M.fromListWith (++) z
where z = zip w $ map (\x -> [x]) $ tail w
w = words text
main :: IO ()
main = do
s <- readFile "c:\\test.hs"let z = fillMark' s
print z
На последний вопрос как лучше сделать я повидимому получил ответ , а как насчет остальных вопросов?
Здравствуйте, Аноним, Вы писали:
А>На последний вопрос как лучше сделать я повидимому получил ответ ,
Ну, можно еще укоротить.
fillMark' :: [String] -> M.Map String [String]
fillMark' words = M.fromListWith (++) $ zip words $ map (:[]) (tail words)
main = readFile "c:\\test.hs" >>= print . fillMark' . words
А>а как насчет остальных вопросов?
Превратить IO Bool в IO () можно так: H.update ... >> return (). Дополнительная функция update не нужна
Про "получить значения обработчиков case" — вопрос не понял.
Здравствуйте, Аноним, Вы писали:
А>Была ошибка, связанная с тем что обработчик Nothing и Just v должны возвращать один тип: А>из — за этого пришлось писать дополнительную функцию update, т.к. H.update возвращает IO Bool, А>как можно короче написать этот код?
H.update m key val >> return ()
А>И автоматически следует следующий вопрос, если обработчики case возвращают значения, то как их можно получить?
Вопрос неясен. case — выражение, поэтому его можно использовать как выражение:
do val <- case expr of
pat1 -> expr1
pat2 -> expr2
...
let x = case v of { Just r -> r ; Nothing -> 0 }
2 + (case cond of { True -> 1 ; False -> 0})
А>Правильно ли написал функцию fill? происходит ее замыкание (вроде правильно сказал)?
fill — это и есть замыкание.
А>И у меня не получилось записать putStr $ show $ H.toList m , как можно это дело записать в одну строчку?
Это я уже показывал
А>И интересует как этот код можно улучшить и в чем оверхед
Здравствуйте, lomeo, Вы писали:
L>map return
Читабельно? Слава-роботам (:[]) хотя бы как идиоматическое выражение воспринимается, а return — это ж надо ещё подумать, что там за монада — List, Maybe или, не дай боже, IO.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, lomeo, Вы писали:
L>>map return К>Читабельно? Слава-роботам (:[]) хотя бы как идиоматическое выражение воспринимается, а return — это ж надо ещё подумать, что там за монада — List, Maybe или, не дай боже, IO.
Ой извини! Что это я, действительно, монады-шмонады?
Я имел в виду map pure, конечно! :)
Re: [Haskell] поясните пример
От:
Аноним
Дата:
06.11.09 06:20
Оценка:
Спасибо всем ответившим.
На счет fill я имел ввиду, что происходит ли его оптимизация в цикл или он все таки съедает стек
Re: [Haskell] поясните пример
От:
Аноним
Дата:
06.11.09 09:05
Оценка:
Если можно то прокоменитируйте следующее продолжение кода. Теперь из полученного мапа требуется сгенерировать текст.
Не совсем ясно где сделать проверку что мап заполнен. Да и genText что то совсем не тянет на чистую функцию Совсем не ясно как правильней сделать randItem, наверное ей надо перередавать список случайных чисел, число которое потребуется известно и будет равно count, хотя это конечно будет зависеть от реализации randItem.
import qualified Data.Map as M
import System.Random
fillMark' :: String -> M.Map String [String]
fillMark' text = M.fromListWith (++) z
where z = zip w $ map (:[]) $ tail w
w = words text
randItem = undefined
genText :: M.Map String [String] -> Int -> String
genText m count = unwords $ take count $ iterate nextWord ""where nextWord word = case M.lookup word m of
Just v -> randItem v
Nothing -> randItem $ M.keys m
main :: IO ()
main = do
s <- readFile "c:\\test.hs"let m = fillMark' s
let t = genText m 50
print t
Здравствуйте, Аноним, Вы писали:
А>Если можно то прокоменитируйте следующее продолжение кода. Теперь из полученного мапа требуется сгенерировать текст. А>Не совсем ясно где сделать проверку что мап заполнен.
Не понятен вопрос. Можно в main сделать, но лучше, наверное, в genText:
genText m _ | M.null m = обработка пустой Map
genText m count = ...
А>Да и genText что то совсем не тянет на чистую функцию
Пока что она вполне чистая
А>Совсем не ясно как правильней сделать randItem, наверное ей надо перередавать список случайных чисел, число которое потребуется известно и будет равно count, хотя это конечно будет зависеть от реализации randItem.
Часто самый простой способ — использовать бесконечный список случайных чисел. Но в данном случае это не очень подходит, т.к. случайные числа надо будет генерировать из различных диапазонов.
В randItem (и в genText) нужно передавать генератор случайных чисел. Создать его можно, например, в main. Из генератора получать случайные числа из нужного диапазона с помощью randomR. Проблема заключается в том, что придется таскать туда-сюда этот генератор (randomR возвращает новый генератор, который должен попасть обратно в genText).
Чтобы этого избежать нужно использовать монаду State. Код значительно упростится. Думаю, надо сначала попробовать сделать в лоб, а потом переписать в State — будет понятнее. Там все не очень сложно — основные функции get, put, evalState.