[Haskell] поясните пример
От: Аноним  
Дата: 05.11.09 09:49
Оценка:
Поясните пару моментов, которые хоть и решил, но все равно остались не понятны
Была ошибка, связанная с тем что обработчик 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
Re: [Haskell] поясните пример
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 05.11.09 10:26
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Поясните пару моментов, которые хоть и решил, но все равно остались не понятны

А>Была ошибка, связанная с тем что обработчик 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. Если уж используешь монады — используй их:

H.toList m >>= putStr . show

или проще

H.toList m >>= print

Ещё раз — перепиши на чистых функциях с Map.
Re: [Haskell] поясните пример
От: Буравчик Россия  
Дата: 05.11.09 11:07
Оценка:
Здравствуйте, Аноним, Вы писали:

А>И интересует как этот код можно улучшить и в чем оверхед


Я так понял задача заключается в том, чтобы построить пары (слово X, список слов которые следуют в тексте за X).
Задача решается в одну-две строчки. Как уже сказал lomeo легче использовать Data.Map
1. С помощью zip строим список пар (слово, слово следующее за ним)
2. Обрабатываем эти пары с помощью Data.Map.insertWith

Если хочется оставаться с HashTable, нужно просто сделать аналог insertWith для HashTable.
Best regards, Буравчик
Re[2]: [Haskell] поясните пример
От: Аноним  
Дата: 05.11.09 11:16
Оценка:
ок, буду пробовать
Re[3]: [Haskell] поясните пример
От: Буравчик Россия  
Дата: 05.11.09 11:45
Оценка:
Здравствуйте, Аноним, Вы писали:

А>ок, буду пробовать


Ой, очепятка! Вместо Data.Map.insertWith нужна функция Data.Map.fromListWith (чтобы не делать лишней работы).
P.S. Напиши, что получилось...
Best regards, Буравчик
р
Re[4]: [Haskell] поясните пример
От: Аноним  
Дата: 05.11.09 12:06
Оценка:
Здравствуйте, Буравчик, Вы писали:
Б>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


На последний вопрос как лучше сделать я повидимому получил ответ , а как насчет остальных вопросов?
Re[5]: [Haskell] поясните пример
От: demao  
Дата: 05.11.09 12:13
Оценка:
Здравствуйте, <Аноним>, Вы писали:

а что более читабельно?
map (\x -> [x])

или
map (:[])
... << RSDN@Home 1.2.0 alpha 4 rev. 1270>>
Re[2]: [Haskell] поясните пример
От: geniepro http://geniepro.livejournal.com/
Дата: 05.11.09 12:38
Оценка:
Здравствуйте, lomeo, Вы писали:

L>2. Используй Data.Map


Ещё стоит попробовать:

"Very fast, scalable mutable maps and hashes for Haskell"
Re[5]: [Haskell] поясните пример
От: Буравчик Россия  
Дата: 05.11.09 13:02
Оценка:
Здравствуйте, Аноним, Вы писали:

А>На последний вопрос как лучше сделать я повидимому получил ответ ,


Ну, можно еще укоротить.
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" — вопрос не понял.
Best regards, Буравчик
Re[3]: [Haskell] поясните пример
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 05.11.09 15:24
Оценка:
Здравствуйте, geniepro, Вы писали:

G>Ещё стоит попробовать:


G>"Very fast, scalable mutable maps and hashes for Haskell"


Очень интересно! Но мой пойнт был в том, что сначала надо сделать задачу в чистых функциях, соптимизировать всегда успеем.
Re[6]: [Haskell] поясните пример
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 05.11.09 15:25
Оценка:
Здравствуйте, demao, Вы писали:

D>а что более читабельно?

D>
D>map (\x -> [x]) 
D>

D>или
D>
D>map (:[]) 
D>


map return
Re: [Haskell] поясните пример
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 05.11.09 15:56
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Была ошибка, связанная с тем что обработчик 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 , как можно это дело записать в одну строчку?


Это я уже показывал

А>И интересует как этот код можно улучшить и в чем оверхед


А на это ты уже сам ответил
Re[7]: [Haskell] поясните пример
От: Кодт Россия  
Дата: 05.11.09 17:50
Оценка: :)
Здравствуйте, lomeo, Вы писали:

L>map return

Читабельно? Слава-роботам (:[]) хотя бы как идиоматическое выражение воспринимается, а return — это ж надо ещё подумать, что там за монада — List, Maybe или, не дай боже, IO.
Перекуём баги на фичи!
Re[8]: [Haskell] поясните пример
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 05.11.09 21:44
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, 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
Re[2]: [Haskell] поясните пример
От: Буравчик Россия  
Дата: 06.11.09 10:07
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Если можно то прокоменитируйте следующее продолжение кода. Теперь из полученного мапа требуется сгенерировать текст.

А>Не совсем ясно где сделать проверку что мап заполнен.

Не понятен вопрос. Можно в 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.
Best regards, Буравчик
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.