Libraries
Table of Contents
1 Libraries
1.1 System Programming in Haskell
Directory
Get current Directory
> import System.Directory > > getCurrentDirectory "/home/tux/PycharmProjects/Haskell" >
Change Current Directory
> import System.Directory > > setCurrentDirectory "/" > > getCurrentDirectory "/" > getCurrentDirectory :: IO FilePath > > > fmap (=="/") getCurrentDirectory True > > liftM (=="/") getCurrentDirectory True >
List Directory Contents
> import System.Directory > > getDirectoryContents "/usr" [".","include","src","local","bin","games","share","sbin","lib",".."] > > :t getDirectoryContents getDirectoryContents :: FilePath -> IO [FilePath] >
Special Directories Location
> getHomeDirectory "/home/tux" > > getAppUserDataDirectory "myApp" "/home/tux/.myApp" > > getUserDocumentsDirectory "/home/tux" >
Running External Commands
> import System.Cmd > > :t rawSystem rawSystem :: String -> [String] -> IO GHC.IO.Exception.ExitCode > > rawSystem "ls" ["-l", "/usr"] total 260 drwxr-xr-x 2 root root 118784 Abr 26 03:38 bin drwxr-xr-x 2 root root 4096 Abr 10 2014 games drwxr-xr-x 131 root root 36864 Mar 11 01:38 include drwxr-xr-x 261 root root 53248 Abr 14 16:46 lib drwxr-xr-x 10 root root 4096 Dez 2 18:55 local drwxr-xr-x 2 root root 12288 Abr 3 13:28 sbin drwxr-xr-x 460 root root 20480 Abr 26 03:38 share drwxr-xr-x 13 root root 4096 Jan 13 21:03 src ExitSuccess >
Reading input from a system command in Haskell
This command executes ls -la and gets the output.
import System.Process test = readProcess "ls" ["-a"] "" > import System.Process > let test = readProcess "ls" ["-a"] "" > > :t test test :: IO String > > test >>= putStrLn . .. adt2.py adt.py build.sh build_zeromq.sh clean.sh codes comparison.ods dict.sh ffi figure1.png .git
1.2 Data.Time
1.2.1 System
1.2.2 Get current year / month / day in Haskell
UTC time:
Note that the UTC time might differ from your local time depending on the timezone.
import Data.Time.Clock import Data.Time.Calendar main = do now <- getCurrentTime let (year, month, day) = toGregorian $ utctDay now putStrLn $ "Year: " ++ show year putStrLn $ "Month: " ++ show month putStrLn $ "Day: " ++ show day
1.2.3 Get Current Time
Local time:
It is also possible to get your current local time using your system’s default timezone:
import Data.Time.Clock import Data.Time.Calendar import Data.Time.LocalTime main = do now <- getCurrentTime timezone <- getCurrentTimeZone let zoneNow = utcToLocalTime timezone now let (year, month, day) = toGregorian $ localDay zoneNow putStrLn $ "Year: " ++ show year putStrLn $ "Month: " ++ show month putStrLn $ "Day: " ++ show day
import Data.Time.Clock import Data.Time.LocalTime main = do now <- getCurrentTime timezone <- getCurrentTimeZone let (TimeOfDay hour minute second) = localTimeOfDay $ utcToLocalTime timezone now putStrLn $ "Hour: " ++ show hour putStrLn $ "Minute: " ++ show minute -- Note: Second is of type @Pico@: It contains a fractional part. -- Use @fromIntegral@ to convert it to a plain integer. putStrLn $ "Second: " ++ show second
1.2.4 Documentation By Examples - GHCI shell
1.2.4.1 Date Time Manipulation
import Data.Time > :t getCurrentTime getCurrentTime :: IO UTCTime > > t <- getCurrentTime > t 2015-03-04 23:22:39.046752 UTC > > :t t t :: UTCTime > today <- fmap utctDay getCurrentTime > today 2015-03-04 > :t today today :: Day > > > let (year, _, _) = toGregorian today > year 2015 > > :t fromGregorian 2015 0 0 fromGregorian 2015 0 0 :: Day > fromGregorian 2015 0 0 2015-01-01 > > diffDays today (fromGregorian year 0 0) 62 > > import Text.Printf > > tm <- getCurrentTime > let (year, month, day) = toGregorian (utctDay tm) > year 2015 > month 3 > day 4 > > printf "The current date is %04d %02d %02d\n" year month day The current date is 2015 03 04 > import System.Locale > > fmap (formatTime defaultTimeLocale "%Y-%m-%d") getCurrentTime "2015-03-04" > >
1.2.4.2 Difference between two dates
> import Data.Time > import Data.Time.Clock.POSIX > > let bree = UTCTime (fromGregorian 1981 6 16) (timeOfDayToTime $ TimeOfDay 4 35 25) -- 1981-06-16 04:35:25 UTC > bree 1981-06-16 04:35:25 UTC > > let nat = UTCTime (fromGregorian 1973 1 18) (timeOfDayToTime $ TimeOfDay 3 45 50) -- 1973-01-18 03:45:50 UTC > nat 1973-01-18 03:45:50 UTC > > > let bree' = read "1981-06-16 04:35:25" :: UTCTime > bree' 1981-06-16 04:35:25 UTC > :t bree' bree' :: UTCTime > > let nat' = read "1973-01-18 03:45:50" :: UTCTime > > nat' 1973-01-18 03:45:50 UTC > > difference = diffUTCTime bree nat / posixDayLength > difference 3071.03443287037s > > "There were " ++ (show $ round difference) ++ " days between Nat and Bree" "There were 3071 days between Nat and Bree" >
1.2.4.3 Day in a Week/Month/Year or Week Number
> import Data.Time > import Data.Time.Calendar.MonthDay > import Data.Time.Calendar.OrdinalDate > import System.Locale > :t fromGregorian fromGregorian :: Integer -> Int -> Int -> Day > let (year, month, day) = (1981, 6, 16) :: (Integer , Int , Int ) > > let date = (fromGregorian year month day) > date 1981-06-16 > > let (week, week_day) = sundayStartWeek date > week 24 > week_day 2 > > let (year_, year_day) = toOrdinalDate date > year_ 1981 > year_day 167 > > let (week_day_name, _) = wDays defaultTimeLocale !! week_day > week_day_name "Tuesday" > > :t defaultTimeLocale defaultTimeLocale :: TimeLocale > > defaultTimeLocale TimeLocale {wDays = [("Sunday","Sun"),("Monday","Mon"),("Tuesday","Tue"),("Wednesday","Wed"),("Thursday","Thu"),("Friday","Fri"),("Saturday","Sat")], months = [("January","Jan"),("February","Feb"),("March","Mar"),("April","Apr"),("May","May"),("June","Jun"),("July","Jul"),("August","Aug"),("September","Sep"),("October","Oct"),("November","Nov"),("December","Dec")], intervals = [("year","years"),("month","months"),("day","days"),("hour","hours"),("min","mins"),("sec","secs"),("usec","usecs")], amPm = ("AM","PM"), dateTimeFmt = "%a %b %e %H:%M:%S %Z %Y", dateFmt = "%m/%d/%y", timeFmt = "%H:%M:%S", time12Fmt = "%I:%M:%S %p"} > >
1.2.4.4 Parsing Dates and Times from Strings
> import Data.Time > import Data.Time.Format > import Data.Time.Clock.POSIX > import System.Locale > let day:: Day ; day = readTime defaultTimeLocale "%F" "1998-06-03" > > day 1998-06-03 >
1.2.4.5 Printing a Date
> import Data.Time > import Data.Time.Format > import System.Locale > > now <- getCurrentTime > :t now now :: UTCTime > > formatTime defaultTimeLocale "The date is %A (%a) %d/%m/%Y" now "The date is Wednesday (Wed) 04/03/2015" > > > let t = do now <- getCurrentTime ; return $ formatTime defaultTimeLocale "The date is %A (%a) %d/%m/%Y" now > t "The date is Wednesday (Wed) 04/03/2015" >
Credits:
1.3 Bytestring
1.3.1 Overview
Bytestring is a built in library for fast and efficient string and binary data processing. ByteStrings are not designed for Unicode. For Unicode strings the Text type must be used from the text package.
There are two flavours of bytestring, the lazy and strict.
- Strict Bytestring: Data.ByteString
String as a single large array, suitable for passing data between C and Haskell.
- Lazy Bytestring: Data.ByteString.Lazy
Lazy list of strict chunks which makes it suitable for I/O streaming tasks
Import Bytestring
To avoid name conflicts the modules must be imported as qualified.
import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy.Char8 as BLC
1.3.2 Example
> import qualified Data.ByteString as B > import qualified Data.ByteString.Char8 as BC > > import qualified Data.ByteString.Lazy as BL > import qualified Data.ByteString.Lazy.Char8 as BLC > > let (|>) x f = f x > {- String to Bytestring -} {---------------------------------------------} > BC.pack "hello world" "hello world" > BC.pack "čušpajž日本語" "\ruapaj~\229,\158" > > :t BC.pack "čušpajž日本語" BC.pack "čušpajž日本語" :: B.ByteString > {- Strict to Lazy Conversion -} {---------------------------------------------} > let s_strict = BC.pack "čušpajž日本語" > s_strict "\ruapaj~\229,\158" > > let s_lazy = BLC.pack "čušpajž日本語" > s_lazy "\ruapaj~\229,\158" > > :t s_ s_lazy s_strict > :t s_lazy s_lazy :: BL.ByteString > {- Strict to Lazy -} > :t BL.fromChunks BL.fromChunks :: [B.ByteString] -> BL.ByteString > > let new_lazy = BL.fromChunks [s_strict] > new_lazy "\ruapaj~\229,\158" > :t new_lazy new_lazy :: BL.ByteString > {- Lazy to Strict -} {---------------------------------------------} > let new_strict = B.concat $ BL.toChunks s_lazy > new_strict "\ruapaj~\229,\158" > :t new_strict new_strict :: B.ByteString > > BC.putStrLn new_strict uapaj~�,� > > BLC.putStrLn new_lazy uapaj~�,� > {- Serialization -} {---------------------------------------------} > import qualified Data.Binary as D > {- Serializes Haskell Data to Lazy Bytestring -} > > :t D.encode D.encode :: D.Binary a => a -> BL.ByteString > > :t D.decode D.decode :: D.Binary a => BL.ByteString -> a > > let a = D.encode 10 > a "\NUL\NUL\NUL\NUL\n" > :t a a :: BL.ByteString > > D.decode a () > D.decode a :: Int *** Exception: Data.Binary.Get.runGet at position 0: demandInput: not enough bytes > D.decode a :: Integer 10 > > let b = D.encode (Just 10 :: Maybe Int) > :t b b :: BL.ByteString > b "\SOH\NUL\NUL\NUL\NUL\NUL\NUL\NUL\n" > > D.decode b :: Maybe Int Just 10 > > let c = D.encode (Nothing :: Maybe Int) > c "\NUL" > > D.decode c :: Maybe Int Nothing > > let d = D.encode (3.11415e4 :: Double) > d "\SOH\SOH\NUL\NUL\NUL\NUL\NUL\NUL\NUL\a\NUL\NUL\NUL\NUL`i\RS\255\255\255\255\255\255\255\218" > {- Bytes to Bytestring -} {---------------------------------------------} {- Bytes are encoded as Word8 -} > :t B.pack B.pack :: [GHC.Word.Word8] -> B.ByteString > :t B.unpack B.unpack :: B.ByteString -> [GHC.Word.Word8] > > :t BL.pack BL.pack :: [GHC.Word.Word8] -> BL.ByteString > :t BL.unpack BL.unpack :: BL.ByteString -> [GHC.Word.Word8] > > let msg = B.pack [72,101,108,108,111,32,119,111,114,108,100] > msg "Hello world" > let bytes = B.unpack msg > bytes [72,101,108,108,111,32,119,111,114,108,100] > > :t msg msg :: B.ByteString > :t bytes bytes :: [GHC.Word.Word8] > {- Word8 to Int -} > :t fromIntegral fromIntegral :: (Num b, Integral a) => a -> b > > let x = 100 :: GHC.Word.Word8 > x 100 > :t x x :: GHC.Word.Word8 > > let y = fromIntegral x :: Int > y 100 > :t y y :: Int > > fromIntegral ( 100 :: GHC.Word.Word8) :: Int 100 > > let bytes_int = map (\x -> fromIntegral x :: Int) bytes > bytes_int [72,101,108,108,111,32,119,111,114,108,100] > :t bytes_int bytes_int :: [Int] > > let bytes_word8 = map (\x -> fromIntegral x :: GHC.Word.Word8) bytes_int > bytes_word8 [72,101,108,108,111,32,119,111,114,108,100] > :t bytes_word8 bytes_word8 :: [GHC.Word.Word8] > {- Bytes in Hexadecimal and Binary Format -} > import Numeric (showHex, showIntAtBase) > import Data.Char (intToDigit) > import Data.Bits (shiftL, shiftR, (.&.), (.|.)) > import Data.Word (Word8) > {- Bytes in Hexadecimal Format Low Endian -} > map (\n -> showHex n "") bytes ["48","65","6c","6c","6f","20","77","6f","72","6c","64"] > > {- Bytes in Hexadecimal Format Big Endian -} > reverse $ map (\n -> showHex n "") bytes ["64","6c","72","6f","77","20","6f","6c","6c","65","48"] > {- Hexadecimal String Low Endian -} > concat $ map (\n -> showHex n "") bytes "48656c6c6f20776f726c64" > {- Hexadecimal String Bing Ending -} > concat $ reverse $ map (\n -> showHex n "") bytes "646c726f77206f6c6c6548" > {- Hexadecimal number to bytes -} > > let num2hex = \n -> showHex n "" > > let x = 0x646c726f77206f6c6c6548 > x 121404708502361365413651784 > > num2hex x "646c726f77206f6c6c6548" > {- Split Bytes -} {-------------------------------------------} > iterate (\x -> shiftR x 8) 0x646c726f77206f6c6c6548 |> takeWhile ((/=) 0) |> map (.&. 0xFF) [72,101,108,108,111,32,119,111,114,108,100] > > map num2hex . map (.&. 0xFF) . takeWhile ((/=) 0) . iterate (\x -> shiftR x 8) $ 0x646c726f77206f6c6c6548 ["48","65","6c","6c","6f","20","77","6f","72","6c","64"] > > iterate (\x -> shiftR x 8) 0x646c726f77206f6c6c6548 |> takeWhile ((/=) 0) |> map (.&. 0xFF) |> map num2hex ["48","65","6c","6c","6f","20","77","6f","72","6c","64"] > > iterate (\x -> shiftR x 8) 0x646c726f77206f6c6c6548 |> takeWhile ((/=) 0) |> map (.&. 0xFF) |> map num2hex |> concat "48656c6c6f20776f726c64" > > iterate (\x -> shiftR x 8) 0x646c726f77206f6c6c6548 |> takeWhile ((/=) 0) |> map (.&. 0xFF) |> map num2hex |> reverse |> concat "646c726f77206f6c6c6548" > > let int2word8 = \x -> fromIntegral x :: Word8 > > let num2bytes = map int2word8 . map (.&. 0xFF) . takeWhile ((/=) 0) . iterate (\x -> shiftR x 8) > :t num2bytes num2bytes :: (Data.Bits.Bits a, Integral a) => a -> [Word8] > > > num2bytes 0x646c726f77206f6c6c6548 [72,101,108,108,111,32,119,111,114,108,100] > > num2bytes 0x646c726f77206f6c6c6548 |> map num2hex ["48","65","6c","6c","6f","20","77","6f","72","6c","64"] > > num2bytes 0x646c726f77206f6c6c6548 |> BL.pack "Hello world" > > {- Bytes to Int -} > let bytes = [72,101,108,108,111,32,119,111,114,108,100] > foldr (\b0 b1 -> (shiftL b1 8) + b0) 0 bytes 121404708502361365413651784 > num2hex . foldr (\b0 b1 -> (shiftL b1 8) + b0) 0 $ bytes "646c726f77206f6c6c6548" > > let bytes2int = foldr (\b0 b1 -> (shiftL b1 8) + b0) 0 > bytes2int bytes 121404708502361365413651784 >
See also
Base64 Algorithm
1.3.3 Documentation in Hackage
ByteString
An efficient compact, immutable byte string type (both strict and lazy) suitable for binary or 8-bit character data.
The ByteString type represents sequences of bytes or 8-bit characters. It is suitable for high performance use, both in terms of large data quantities, or high speed requirements. The ByteString functions follow the same style as Haskell's ordinary lists, so it is easy to convert code from using String to ByteString.
Data.Word
Unsigned integer types: Word8, Word16, Word32, Word64
Data.Binary package
Binary serialisation of Haskell values to and from lazy ByteStrings. The Binary library provides methods for encoding Haskell values as streams of bytes directly in memory. The resulting ByteString can then be written to disk, sent over the network, or futher processed (for example, compressed with gzip).
Data.Bits package
This module defines bitwise operations for signed and unsigned integers. Instances of the class Bits for the Int and Integer types are available from this module, and instances for explicitly sized integral types are available from the Data.Int and Data.Word modules.
Numeric
Odds and ends, mostly functions for reading and showing RealFloat-like kind of values.
Data.Char
The Char type and associated operations.
1.4 Parse Binary Files
To decode a binary file it is necessary to know:
- The Binary file format or specification
- File Signature that comes in the file header.
- Data Size (8 bits signed, 8 bits unsigned, ….)
- Byte Endianess or Byte order (Little Endian or Big Endian)
This section will show how to parse the windows executable, PE32 executable.
PE32 Layout Specification
- Undocumented PECOFF - Reversing Labs
- https://en.wikipedia.org/wiki/Portable_Executable
- http://www.csn.ul.ie/~caolan/publink/winresdump/winresdump/doc/pefile.html
import Data.Word --- Unsigned integer types: Word8, Word16, Word32, Word64 import Data.ByteString.Lazy as BL import Data.ByteString.Char8 as BC import Data.Binary import Data.Binary.Get > let (|>) x f = f x > > :t BL.readFile BL.readFile :: FilePath -> IO BL.ByteString > fdata <- BL.readFile "notepad.exe" > > :t fdata fdata :: BL.ByteString > > :t BL.take BL.take :: GHC.Int.Int64 -> BL.ByteString -> BL.ByteString {- Read File Signare 2 bytes, always 0x5A4D OR ("MZ") - -} > BL.take 2 fdata "MZ" > > let toHex :: [Word8] -> [String] ;toHex = Prelude.map ( (\n -> showHex n "") . (\x -> fromIntegral x :: Int) ) > > BL.take 2 fdata |> BL.unpack |> toHex ["4d","5a"] > read_dosHeader = do
PE32 Documentation
Dos Header Structure
From:
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file WORD e_cp; // Pages in file WORD e_crlc; // Relocations WORD e_cparhdr; // Size of header in paragraphs WORD e_minalloc; // Minimum extra paragraphs needed WORD e_maxalloc; // Maximum extra paragraphs needed WORD e_ss; // Initial (relative) SS value WORD e_sp; // Initial SP value WORD e_csum; // Checksum WORD e_ip; // Initial IP value WORD e_cs; // Initial (relative) CS value WORD e_lfarlc; // File address of relocation table WORD e_ovno; // Overlay number WORD e_res[4]; // Reserved words WORD e_oemid; // OEM identifier (for e_oeminfo) WORD e_oeminfo; // OEM information; e_oemid specific WORD e_res2[10]; // Reserved words LONG e_lfanew; // File address of new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
COFF Header
struct COFFHeader { short Machine; short NumberOfSections; long TimeDateStamp; long PointerToSymbolTable; long NumberOfSymbols; short SizeOfOptionalHeader; short Characteristics; }
1.5 GnuPlot
Installation:
$ cabal install gnuplot $ sudo apt-get install gnuplot-x11 # Ubuntu/ Debian
Examples:
> import Graphics.Gnuplot.Simple > plotList [] [(1, 1), (2, 2), (3, 3)]
> import Graphics.Gnuplot.Simple > plotFunc [] (linearScale 1000 (-20,20)) (\x -> sin x / x)
> plotList [Title "A title", XLabel "x label"] [(2,10),(3,15),(4,14),(5,19)] > plotList [Title "A title", XLabel "x label", YLabel "the y label"] [(2,10),(3,15),(4,14),(5,19)]
Doucumentation
This is a wrapper to gnuplot which lets you create 2D and 3D plots. Start a simple session with make ghci. This loads the module Graphics.Gnuplot.Simple which is ready for use in GHCi. It does not address all fancy gnuplot features in order to stay simple. For more sophisticated plots, especially batch generated graphics, I recommend Graphics.Gnuplot.Advanced. This module contains also an overview of the hierarchy of objects.