В моем посте части 1 на эту тему мы фактически сделали все операции ввода-вывода, которые я собираюсь сделать здесь. Мы лениво читаем весь пример файла данных, файл, содержащий данные, описывающие события, генерируемые монитором процесса. Моя следующая цель состояла в том, чтобы повторно гидрировать мои события из строки, сериализованной в файл. Эти строки s были получены с помощью вызова функции шоу в моем списке из событий s.
Время немного подкрепиться. Мы получили шоу бесплатно, но мы должны были попросить его. Оставив на некоторое время тип данных Event и остановившись на более простом типе данных Property , вспомните, как мы его определили:
data Property = Property { key :: Key, value:: Value } deriving (Show)
В то время мы обсуждали «
получение (показ) », просто отметив, что это позволяет
ghci знать, как выводить
значения свойств . Конечно, это еще не все. «Больше» — это классы типов Haskell. Класс типов Haskell определяет набор функций, которые могут быть определены для работы с типом данных. Функция
show является членом класса
типов Show и имеет следующий тип:
*EventProcessor> :type show show :: Show a => a -> String
На мгновение посмотрим, что произошло, если мы не указали, что
Property наследует
Show :
-- file: c:/HaskellDev/eventProcessor/simpleProperty.hs type Key = String type Value = String data Property = Property { key :: Key, value:: Value }
Если мы загрузим этот файл, затем создадим
свойство , а затем попробуем его
показать , мы увидим следующее:
Prelude> :load simpleProperty.hs [1 of 1] Compiling Main ( simpleProperty.hs, interpreted ) Ok, modules loaded: Main. *Main> let prop1 = Property "key1" "value1" *Main> show prop1 :1:1: No instance for (Show Property) arising from a use of `show' Possible fix: add an instance declaration for (Show Property) In the expression: show prop1 In an equation for `it': it = show prop1
Это значительно более полезно, чем типичное сообщение об ошибке компилятора. Ключ подсказка для добавления объявления экземпляра. Чтобы функции класса типов были применимы к вашему типу данных, вам необходимо объявить экземпляр этого класса типов, который обрабатывает ваш тип данных. В нашем случае мы можем получить
Show, просто заявив, что мы его выводим. Итак, мы вернемся к нашему старому определению:
-- file: c:/HaskellDev/eventProcessor/simpleProperty.hs type Key = String type Value = String data Property = Property { key :: Key, value:: Value } deriving (Show)
Повторяя наш предыдущий тест, теперь мы получаем следующее:
*Main> :load simpleProperty.hs [1 of 1] Compiling Main ( simpleProperty.hs, interpreted ) Ok, modules loaded: Main. *Main> let prop1 = Property "key1" "value1" *Main> show prop1 "Property {key = \"key1\", value = \"value1\"}"
Это определенно улучшение. Но вернемся к теме — я хочу прочитать
строку и передать ее в
свойство . Во-первых, давайте попробуем прочитать
строку в
целое число :
*Main> read "5" :1:1: Ambiguous type variable `a0' in the constraint: Read a0) arising from a use of `read' Probable fix: add a type signature that fixes these type variable(s) In the expression: read "5" In an equation for `it': it = read "5"
Опять же, полезный совет от
ghci . По сути, он не знает, что мы пытаемся создать, и предлагает добавить сигнатуру типа. Вот как бы вы это сделали:
*Main> let anInt = (read "5")::Integer *Main> :type anInt anInt :: Integer *Main> show anInt "5"
Теперь Haskell знает, что мы пытаемся прочитать
Integer , поэтому он распознает, что
anInt является
Integer, и знает, как его
показать . Все это должно сказать вам, что
Integer определил экземпляры для
Show и
Read .
Можем ли мы получить
Read «бесплатно», просто заявив, что наш тип данных получает его? Не больно пытаться:
-- file: c:/HaskellDev/eventProcessor/simpleProperty.hs type Key = String type Value = String data Property = Property { key :: Key, value:: Value } deriving (Read, Show)
Далее я создам
свойство и выводит его с
шоу , а затем увидеть , если этот формат (который, кстати, как я создал свой образец
Event файл — с помощью шоу на
список из
событий s) является «
чтения » -able:
*Main> let prop1 = Property "key1" "value1" *Main> show prop1 "Property {key = \"key1\", value = \"value1\"}" *Main> let prop2 = (read "Property {key = \"key1\", value = \"value1\"}")::Property *Main> show prop2 "Property {key = \"key1\", value = \"value1\"}"
Это хорошая новость — мне не нужно было писать анализатор, и я совершенно счастлив использовать в качестве моего формата тот же формат, который использует Haskell для
отображения структуры данных Haskell.
То , что я бы очень хотел , чтобы сделать это , чтобы быть в состоянии прочитать полное
событие , как это определено в моих предыдущих сообщений, в том числе
список из
событий s. Вот пример
события :
"Event {timestamp = 1320512200548, className = \"java.lang.String\", lineNumber = 1293, message = \"NPE in substring()\", properties = [Property {key = \"userId\", value = \"smith\"}, Property {key = \"sessionId\", value = \"ABCD1234\"}]}"
Давайте попробуем тот же трюк с
Event, который мы использовали с
Property :
-- file: c:/HaskellDev/eventProcessor/notSoSimpleProperty.hs type Timestamp = Integer type ClassName = String type LineNumber = Integer type Message = String type Key = String type Value = String type Properties = [Property] data Property = Property { key :: Key, value:: Value } deriving (Read, Show) data Event = Event { timestamp :: Timestamp, className :: ClassName, lineNumber :: LineNumber, message :: Message, properties :: Properties } deriving (Read, Show)
Достаточно ли было просто объявить, что
Событие происходит от
Show ? Давайте посмотрим:
*EventProcessor> :load notSoSimpleProperty.hs [1 of 1] Compiling Main ( notSoSimpleProperty.hs, interpreted ) Ok, modules loaded: Main. *Main> let event1 = (read "Event {timestamp = 1320512200548, className = \"java.lang.String\",
lineNumber = 1293, message = \"NPE in substring()\", properties = [Property {key = \"userId\", value = \"smith\"},
Property {key = \"sessionId\", value = \"ABCD1234\"}]}")::Event *Main> show event1 "Event {timestamp = 1320512200548, className = \"java.lang.String\", lineNumber = 1293, message = \"NPE in substring()\",
properties = [Property {key = \"userId\", value = \"smith\"},Property {key = \"sessionId\", value = \"ABCD1234\"}]}" *Main> show (properties event1) "[Property {key = \"userId\", value = \"smith\"},Property {key = \"sessionId\", value = \"ABCD1234\"}]"
Это здорово. Мы можем взять
строковое представление
события как вывод от
show и использовать его непосредственно с
read для создания экземпляра
переменной Event .
Это обсуждение никоим образом не описывает, как предоставить экземпляр класса типов; возможно в другом посте. Сейчас я все еще хочу создать
Event s из моего примера
файла Event .
Мое первое сокращение в этом заключается в следующем:
import System.IO import EventProcessor main :: IO () main = do inh <- openFile "sampleEvents" ReadMode inContents <- hGetContents inh let eventList = processData (lines inContents) hClose inh processData :: [String] -> [Event] processData = map createEvent createEvent :: String -> Event createEvent event = (read event)::Event
В то время как это кажется правильным, это ничего , что доказывает , что я смог разобрать мои строки примера-файлы в не сделать
список из
событий s. К сожалению, на данный момент я немного застрял, так как я еще не понял, как правильно извлекать элементы из
событий Event s (я могу сделать это в интерактивном режиме в
ghci , но меня мучают ошибки компилятора, если я пытаюсь это сделать так в
блоке do ).
Я собираюсь оставить это на некоторое время и вернуться к некоторым онлайн-ресурсам / учебным пособиям, а затем вернуться к ним. Проблема для меня в том, что я до сих пор не понимаю монаду ввода / вывода, как она называется. Мне становится ясно, что концепция монады — очевидно, настолько неотъемлемая для Хаскеля — нелегко понять, о чем свидетельствует подавляющее количество онлайн-уроков «Вот мой взгляд на монады» (одного автора, я вижу шутит, что каждый, кто узнает о монадах, вскоре после этого публикует учебник по этой теме). Поэтому я отправляюсь на Haskell Wiki, чтобы узнать о монадах, затем узнать больше о вводе-выводе Haskell, а затем продолжить с того места, где я остановился.
С http://wayne-adams.blogspot.com/2011/12/from-oo-to-fp-haskell-io-part-2.html