|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Меню:
Главная
Форум
Литература: Программирование и ремонт Импульсные блоки питания Неисправности и замена Радиоэлектронная аппаратура Микросхема в ТА Рубрикатор ТА Кабельные линии Обмотки и изоляция Радиоаппаратура Гибкие диски часть 2 часть 3 часть 4 часть 5 Ремонт компьютера часть 2 Аналитика: Монтаж Справочник Электроника Мощные высокочастотные транзисторы 200 микросхем Полупроводники ч.1 Часть 2 Алгоритмические проблемы 500 микросхем 500 микросхем Сортировка и поиск Монады Передача сигнала Электроника Прием сигнала Телевидиние Проектирование Эвм Оптимизация Автомобильная электроника Поляковтрансиверы Форт Тензодатчик Силовые полевые транзисторы Распределение частот Резисторные и термопарные Оберон Открытые системы шифрования Удк |
[21] ds <- gets desc return $ (elem a as) && (elem d ds) -add a Queen to the board in all allowed positions addQueens :: NDS () addQueens = do rs <- gets ranks fs <- gets files allowed <- filterM inDiags [Pos f r f <- fs, r <- rs] tell [show (length allowed) ++ " possible choices"] msum (map addQueen allowed) -Start with an empty chess board and add the requested number of queens, -- then get the board and print the solution along with the log main :: IO () main = do args <- getArgs let n = read (args!!0) cmds = replicate n addQueens sol = ("getSolution" initialState) $ do sequence cmds gets board case sol of Just (b,l) -> do putStr $ show b -- show the solution putStr $ unlines l -- show the log Nothing -> putStrLn "No solution" The program operates in a similar manner to the previous example, which solved the kalotan puzzle. In this example, however, we do not test for consistency using the guard function. Instead, we only create branches that correspond to allowed queen positions. We use the added logging facility to log the number of possible choices at each step and the position in which the queen was placed. 3.7.3. Heavy lifting There is one subtle problem remaining with our use of multiple monad transformers. Did you notice that all of the computations in the previous example are done in the combined monad, even if they only used features of one monad? The code for these functions in tied unneccessarily to the definition of the combined monad, which decreases their reusability. This is where the lift function from the MonadTrans class comes into its own. The lift function gives us the ability to write our code in a clear, modular, reusable manner and then lift the computations into the combined monad as needed. Instead of writing brittle code like: logString :: String -> StateT MyState (WriterT [String] []) Int logString s = ... we can write clearer, more flexible code like: logString :: (MonadWriter [String] m) => String -> m Int
£ сс logString s = ... and then lift the logString computation into the combined monad when we use it. You may need to use the compiler flags -fglasgow-exts with GHC or the equivalent flags with your Haskell compiler to use this technique. The issue is that m in the constraint above is a type constructor, not a type, and this is not supported in standard Haskell 98. When using lifting with complex transformer stacks, you may find yourself composing multiple lifts, like lift. lift. lift $ f x. This can become hard to follow, and if the transformer stack changes (perhaps you add ErrorT into the mix) the lifting may need to be changed all over the code. A good practice to prevent this is to declare helper functions with informative names to do the lifting: liftListToState = lift . lift . lift Then, the code is more informative and if the transformer stack changes, the impact on the lifting code is confined to a small number of these helper functions. The hardest part about lifting is understanding the semantics of lifting computations, since this depends on the details of the inner monad and the transformers in the stack. As a final task, try to understand the different roles that lifting plays in the following example code. Can you predict what the output of the program will be? Code available in example26.hs - this is our combined monad type for this problem type NDS a = StateT Int (WriterT [String] []) a {- Here is a computation on lists -} -- return the digits of a number as a list getDigits :: Int -> [Int] getDigits n = let s = (show n) in map digitToInt s {- Here are some computations in MonadWriter -} -- write a value to a log and return that value logVal :: (MonadWriter [String] m) => Int -> m Int logVal n = do tell ["logVal: " ++ (show n)] return n -- do a logging computation and return the length of the log it wrote getLogLength :: (MonadWriter [[a]] m) => m b -> m Int getLogLength c = do ( ,l) <- listen $ c return (length (concat l))
logString :: (MonadWriter [String] m) => String -> m Int logString s = do tell ["logString: " ++ s] return 0 {- Here is a computation that requires a WriterT [String] [] -} -"Fork" the computation and log each list item in a different branch. logEach :: (Show a) => [a] -> WriterT [String] [] a logEach xs = do x <- lift xs tell ["logEach: " ++ (show x)] return x {- Here is a computation in MonadState -} -increment the state by a specified value addVal :: (MonadState Int m) => Int -> m () addVal n = do x <- get put (x+n) {- Here are some computations in the combined monad -} -- set the state to a given value, and log that value setVal :: Int -> NDS () setVal n = do x <- lift $ logVal n put x -- "Fork" the computation, adding a different digit to the state in each branch. -Because setVal is used, the new values are logged as well. addDigits :: Int -> NDS () addDigits n = do x <- get y <- lift . lift $ getDigits n setVal (x+y) {- an equivalent construction is: addDigits :: Int -> NDS () addDigits n = do x <- get msum (map (\i->setVal (x+i)) (getDigits n)) {- This is an example of a helper function that can be used to put all of the lifting logic in one location and provide more informative names. This has the advantage that if the transformer stack changes in the future (say, to add ErrorT) the changes to the existing lifting logic are confined to a small number of functions.
|
Среды: Smalltalk80 MicroCap Local bus Bios Pci 12С ML Микроконтроллеры: Atmel Intel Holtek AVR MSP430 Microchip Книги: Емкостный датчик 500 схем для радиолюбителей часть 2 (4) Структура компьютерных программ Автоматическая коммутация Кондиционирование и вентиляция Ошибки при монтаже Схемы звуковоспроизведения Дроссели для питания Блоки питания Детекторы перемещения Теория электропривода Адаптивное управление Измерение параметров Печатная плата pcad pcb Физика цвета Управлении софтверными проектами Математический аппарат Битовые строки Микроконтроллер nios Команды управления выполнением программы Перехода от ahdl к vhdl Холодный спай Усилители hi-fi Электронные часы Сердечники из распылённого железа Анализ алгоритмов 8-разрядные КМОП Классификация МПК История Устройства автоматики Системы и сети Частотность Справочник микросхем Вторичного электропитания Типы видеомониторов Радиобиблиотека Электронные системы Бесконтекстный язык Управление техническими системами Монтаж печатных плат Работа с коммуникациями Создание библиотечного компонента Нейрокомпьютерная техника Parser Пи-регулятор ч.1 ПИ-регулятор ч.2 Обработка списков Интегральные схемы Шина ISAВ Шина PCI Прикладная криптография Нетематическое: Взрывной автогидролиз Нечеткая логика Бытовые установки (укр) Автоматизация проектирования Сбор и защита Дискретная математика Kb радиостанция Энергетика Ретро: Прием в автомобиле Управление шаговым двигателем Магнитная запись Ремонт микроволновки Дискретные системы часть 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||