Haskell
Language
module Main (main) where import qualified System.IO as IO main :: IO () main = IO.putStr "Hello, World!"
- https://www.simplehaskell.org/
- Haskell Fan Site https://theory.stanford.edu/~blynn/haskell/
- Mailing List https://mail.haskell.org/mailman/listinfo/haskell-cafe
- https://www.schoolofhaskell.com/school/advanced-haskell/beautiful-concurrency/3-software-transactional-memory
- https://github.com/prathyvsh/category-theory-resources
- https://work.njae.me.uk/2021/12/21/advent-of-code-2021-day-19/
- http://sordina.github.io/blog/2021/01/03/1609638326-advent19b.html
- Usage Examples of Haskell https://homepages.inf.ed.ac.uk/wadler/realworld/
- Memory Usage https://stackoverflow.com/questions/459725/how-to-reduce-memory-usage-in-a-haskell-app
- FPGA Clash Talks https://unsafeperform.io/talks/
- https://hoogle.haskell.org/
- https://github.com/graninas/software-design-in-haskell
- https://en.wikipedia.org/wiki/Dependent_type
- https://en.wikipedia.org/wiki/Generalized_algebraic_data_type
- tutorial http://caiorss.github.io/Functional-Programming/haskell/README.html
deriving - types that can be derived
type | for types that… |
---|---|
Bounded | with finite upper and lower bounds |
Eq | can be compared for equality |
Ord | have a total ordering (extends Eq) |
Ix | support indexing into a range |
Read | can be parsed from strings |
Show | can be converted into strings |
Enum | can be converted to and from integers |
pragmas
LANGUAGE | to enable language extensions |
MINIMAL | to define the minimal functions that should be defined on a class, comma separated, supports (¦) |
module (and exports)
- each file contains a module
- the basic unit of organization in Haskell
- the module
Main
that defines main, can have any filename - src/Examples/ExampleOne.hs -> Examples.ExampleOne
CODE | DESCRIPTION |
---|---|
module ModuleName where | by default, exports ALL |
module ModuleName ( | exports foo |
foo | |
TypeFoo(TypeFooConst, fieldSelector) | |
) where | |
module ModuleName ( | exports all constructors and fieldselectors |
TypeFoo(..) | of TypeFoo |
) where | |
module ModFoo | re-exporting ModBar, |
( module Baz | using the local alias "Baz" |
) | could have used the original name instead |
where | |
import Other.ModBar as Baz |
imports
example | description | |
---|---|---|
import ALL | import Data.List | brings everything in |
import () | import Data.List (intercalate) | brings ONLY … |
as | import Data.ByteString as BS | brings everything in AND under BS. |
as qualified | import qualified Data.ByteString as BS | brings it only under BS. |
hiding | import Prelude hiding (foldl, foldr) | brings ALL except … |
type import | import Data.Text (Text) | to use Text type identifier directly |
+ qualified | import qualified Data.Text as T |
- you can assign the same import (as) alias to different modules
- NOTE: here "brings" means, get it into this module's direct access
operators
simples
$ | function application | map ($ 10) [(+ 1)] | ||
$! | strict function application | |||
. | function composition | printLn . show | ||
++ | append lists | [1,2] ++ [3,4] | [1,2,3,4] | [a] -> [a] -> [a] |
<> | append strings (mappend) | "foo" <> "bar" | "foobar" | m -> m -> m |
!! | list indexing | [1,2] !! 0 | 1 | [a] -> Int -> a |
: | list consing, preppending | 1 : [2, 3] | [1,2,3] | a -> [a] -> [a] |
== | equal | 1 == 2 | False | a -> a -> Bool |
/= | not equal | 1 == 2 | True | a -> a -> Bool |
typeclasses
op | description | fn signature | |
---|---|---|---|
<> | mappend | Semigroup a | a -> a -> a |
<$> | fmap | Functor f | (a -> b) -> f a -> f b |
>>= | bind | Monad m | m a -> (a -> m b) -> m b |
=<< | flipped bind | Monad m | (a -> m b) -> m a -> m b |
>> | then | Monad m | m a -> m b -> m b |
>=> | monadic composition, fish op | Monad m | (a -> m b) -> (b -> m c) -> (a -> m c) |
<=< | flipped kleiski fish | Monad m | (b -> m c) -> (a -> m b) -> (a -> m c) |
<$ | Functor f | a -> f b -> f a | |
<¦> | Control.Alternative | Alternative f | f a -> f a -> f a |
<*> | apply | Applicative f | f (a -> b) -> f a -> f b |
*> | left "facing bird"/shark | Applicative f | f a -> f b -> f b |
<* | right "facing bird"/shark | Applicative f | f a -> f b -> f a |
types
type String = [Char] -- a type alias -- can only have ONE contructor with ONE argument -- can be made an instance newtype StepName = StepName Text deriving (Eq, Show) data Pipeline = Pipeline { steps :: [Step] } deriving (Eq, Show)
types primitives
type | eg | description | |
---|---|---|---|
Bool | True | boolean, short-circuits due laziness | |
Integer | 2 | signed integer, unbounded | |
Int | 2 | signed integer, 32/64 bit | |
Word | 2 | unsigned integer, 32/64 bit | |
Float | 1.2 | IEEE single-precision floating-point | |
Double | 1.2 | IEEE double-precision floating-point | |
Char | 'A' | an unicode code point | Data.Char |
'\9835' | |||
String | "foo" | list characters | |
Ratio | 1 % 3 | Data.Ratio |
- String
string gaps
within a string literal, two backslashes with a whitespace between them form a gap in the string. Removed during compilation."Your password cannot be \ \longer than 20 characters."
types complex
instancing | possible definition | name | description |
---|---|---|---|
[1,2] | [Int] | (linked) list | |
"foo" | type A = String | type alias | |
0 :¦ [1,2] | data NonEmpty a = a :¦ [a] | non empty list | Data.List.NonEmpty |
A "foo" | newtype A = A String | type "safe" alias | can have only 1 type |
no alternatives | |||
C "foo" | data A a | data | can have >1 type per construct |
= C String Int | |||
¦ D a | can have alternatives with ¦ | ||
C {foo = 1} | data A = C { foo :: Int } | data records | automatically creates getters |
avoid clashes by prefixing field names | |||
syntax to update a field | |||
x1 {foo = 2} | |||
Tuple 2 "foo" | data Tuple a b = Tuple a b | data tuple | we are able to plug differen types |
(2, "foo") | polymorphic definition | ||
Left "Hello" | data Either a b | useful for modeling errors | |
Right 17 | = Left a | Right = we got what we wanted | |
¦ Right b | Left = we got an error |
- tuples (aka anonymous products)
Standard Library
Prelude.hs functions
fn | returns | description |
---|---|---|
all | Bool | |
any | Bool | |
concatMap | [a] | map + concat |
dropWhile | [a] | drops from head while fn is True |
filter | [a] | |
uncurry | (a,b) -> c | takes a fn that takes 2 args, and returns a fn that takes a pair |
curry | a -> b -> c | takes a fn that takes a pair, and returns a fn that takes 2 args |
flip | b -> a -> c | returns the same function with argumnts flipped |
fold | t m -> m | folds a Foldable+Monoid |
foldl | a | folds left |
foldl1 | a | folds left over NON EMPTY lists |
foldr | a | folds right |
foldr1 | a | folds right over NON EMPTY lists |
iterate | [a] | returns the infinity list of applying [fn x, fn (fn x),…] |
map | [b] | |
span | ([a],[a]) | split list into 2 tuple, pivot when fn returns False |
break | ([a],[a]) | split list into 2 tuple, pivot when fn returns True |
takeWhile | [a] | returns elems from head, while fn returns True |
until | [a] | returns elems from head, until fn returns False |
zipWith | [c] | applies a binary function and two list |
repeat | [a] | repeats an infinite in an list, the value provided |
replicate | [a] | repeats N-times in a list, the value provided |
concat | [a] | flattens a list of lists |
head | a | first element on a NON EMPTY list |
tail | [a] | aka cdr |
last | a | last element on a NON EMPTY list |
init | [a] | aka butlast |
sort | [a] | sorts in ascending order |
reverse | [a] | reverse a list |
maximum | a | returns max element on a NON EMPTY list |
minimum | a | returns min element on a NON EMPTY list |
length | int | |
null | Bool | true if empty list |
and | Bool | applied to a list of booleans |
or | Bool | applied to a list of booleans |
product | int | aka reduce #'* |
sum | int | aka reduce #'+ |
++ | [a] | append 2 lists |
zip | [(a,b)] | applied to 2 lists, returns a list of pairs |
elem | Bool | aka exists? on list |
notElem | Bool | aka NOT exists? on list |
!! | a | indexing a list |
splitAt | ([a],[a]) | splits at index |
take | a | aka subseq 0 N |
drop | [a] | aka nthcdr |
lines | [String] | split String by new line |
unlines | String | list of strings into string |
words | [String] | |
unwords | String | |
digitToInt | Int | char to int |
chr | Char | takes an integer |
ord | Int | ascii code for char |
toLower | Char | |
toUpper | Char | |
compare | Ordering | |
error | a | takes a string and errors |
max | a | max between 2 elements |
succ | a | next value on an Enum, error if last |
pred | a | previous value on an Enum, error if first |
fst | a | first element on a two element tuple |
snd | b | second element on a two element tuple |
maybe | b | applied fn to Maybe value, or the default value provided |
IO () | putStrLn . show | |
putChar | IO () | |
putStr | IO () | prints string |
show | String | |
isSpace | Bool | |
isAlpha | Bool | if char is alphabetic |
isDigit | Bool | if char is a number |
isLower | Bool | |
isUpper | Bool | |
ceiling | smallest integer, not less than argument | |
floor | greatest integer, not greater than argument | |
round | nearest integer | |
truncate | drops the fractional part | |
mod | ||
quot | ||
rem | ||
** | Floating | raises, arguments must be Floating |
^ | Num | raises, Num by Integral |
^^ | Fractional | raises, Fractional by Integral |
base
module / description | fn | |
---|---|---|
Control.Applicative | ||
Control.Arrow | ||
Control.Category | ||
Control.Concurrent | ||
forkIO | IO () -> IO ThreadedId | |
Control.Concurrent.MVar | a synchronization variable (mutex?) | |
newMVar | IO (MVar a) | |
newEmptyMVar | IO (MVar a) | |
readMVar | MVar a -> IO a | |
MVar a -> IO a | ||
MVar a -> a -> IO () | ||
tryReadMVar | MVar a -> IO (Maybe a) | |
tryTakeMVar | MVar a -> IO (Maybe a) | |
modifyMVar | MVar a -> (a -> IO (a,b)) -> IO b | |
Control.Concurrent.Chan | newChan | IO (Chan a) |
writeChan | Chan a -> a -> IO () | |
readChan | Chan a -> IO a | |
Control.Exception | ||
catch | Exception e => IO a -> (e -> IO a) -> IO a | |
handle | Exception e => (e -> IO a) -> IO a -> IO a | |
ioError | IOError -> IO a | |
throw | Exception e => e -> a | |
throwIO | Exception e => e -> IO a | |
acq,rel,use of resource | bracket | IO r -> (r -> IO a) -> (r -> IO b) -> IO b |
bracket_ | IO a -> IO b -> IO c -> IO c | |
Control.Exception.Safe | tryAny | IO a -> IO (Either SomeException a) |
Control.Monad | ||
"flattens" a monad | join | Monad m => m (m a) -> m a |
monadic composition | >=> | Monad m => (a -> m b) -> (b -> m c) -> a -> m c |
<=< | Monad m => (b -> m c) -> (a -> m b) -> a -> m c | |
<$ | Functor f => a -> f b -> f a | |
repeats input IO () | forever | Applicative f => f a -> f b |
could take IO () | when | Applicative f => Bool -> f () -> f () |
guard | Alternative f => Bool -> f () | |
could take [IO ()] | sequence | (Monad m, Traversable t) => t (m a) -> m (t a) |
sequence_ | (Monad m, Foldable t) => t (m a) -> m () | |
sequence $ map f | mapM | (Monad m, Traversable t) => (a -> m b) -> t a -> m (t b) |
same but no return | mapM_ | (Monad m, Foldable t ) => (a -> m b) -> t a -> m () |
flipped mapM | forM | (Monad m, Traversable t) => t a -> (a -> m b) -> m (t b) |
forM_ | (Monad m, Foldable t ) => t a -> (a -> m b) -> m () | |
aka fmap | liftM | Monad m => (a -> b) -> m a -> m b |
aka <$> (applicative) | ap | Monad m => m (a -> b) -> m a -> m b |
filterM | Monad m => (a -> m Bool) -> [a] -> m [a] | |
discards the result | void | Functor f => f a -> f () |
Control.Monad.IO.Class | liftIO | IO a -> m a |
Control.Monad.Fail | fail | MonadFail m => String -> m a |
Data.Bifoldable | ||
Data.Bifoldable1 | ||
Data.Bifunctor | ||
Data.Bitraversable | ||
Data.Bits | ||
Data.Bool | ||
Data.Char | isPrint | |
ord | Char -> Int | |
chr | Int -> Char | |
Data.Coerce | ||
Data.Complex | ||
Data.Data | ||
Data.Dynamic | ||
Data.Either | ||
Data.Eq | ||
Data.Fixed | ||
Data.Foldable | for_ | (Foldable t, Applicative f) => t a -> (a -> f b) -> f () |
Data.Foldable1 | ||
Data.Function | ||
Data.Functor | ||
Data.IORef | ||
Data.Int | Int8/64 | |
Data.Ix | ||
Data.Kind | ||
Data.List | permutations splitAt | |
Data.Maybe | ||
apply f, with default b | maybe | b -> (a -> b) -> Maybe a -> b |
mapMaybe | (a -> Maybe b) -> [a] -> [b] | |
listToMaybe | [a] -> Maybe a | |
maybeToList | Maybe a -> [a] | |
Data.Fixed | mod' | Real a => a -> a -> a |
Data.Monoid | ||
Data.Ord | ||
Data.Proxy | ||
Data.Ratio | ||
Data.STRef | ||
Data.Semigroup | ||
Data.String | ||
Data.Traversable | ||
Data.Tuple | ||
Data.Typeable | ||
Data.Unique | ||
Data.Version | ||
Data.Void | ||
Data.Word | ||
Debug.Trace | ||
print dynamic msg 1°arg | trace | String -> a -> a |
print static msg | traceId | String -> String |
traceShow | Show a => a -> b -> b | |
traceShowId | Show a => a -> a | |
Foreign | interfacing with another programming language | |
Foreign.C.Types | CInt, CUint | |
Foreign.Ptr | nullPtr | Ptr a |
castPtr | Ptr a -> Ptr b | |
plusPtr | Ptr a -> Int -> Ptr b | |
Foreign.Marshall.Alloc | allocaBytes | Int -> (Ptr a -> IO b) -> IO b |
mallocBytes | Int -> IO (Ptr a) | |
Foreign.Marshal.Utils | copyBytes | Ptr a -> Ptr a -> Int -> IO () |
Foreign.Storable | peek | Ptr a -> IO a |
peekByteOff | Ptr b -> Int -> IO a | |
GHC.Float | float2Int | Float -> Int |
int2Float | Int -> Float | |
Numeric.Natural | Natural | a type of non negative number |
minusNaturalMaybe | Natural -> Natural -> Maybe Natural | |
System.CPUTime | ||
System.Console | ||
System.Environment | getArgs | IO [String] |
withArgs | [String] -> IO a -> IO a | |
System.Exit | ||
data ExitCode | = ExitSuccess ¦ ExitFailure Int | |
stderr msg+exitFailure | die | String -> IO a |
exitWith | ExitCode -> IO a | |
exitSuccess | IO a | |
exitFailure | IO a | |
System.Info | ||
System.Mem | ||
System.Posix | ||
System.Timeout | ||
System.IO | openFile | FilePath -> IOMode -> IO Handle |
withFile | FilePath -> IOMode -> (Handle -> IO r) -> IO r | |
openBinaryFile | FilePath -> IOMode -> IO Handle | |
hSetBinaryMode | Handle -> Bool -> IO () | |
hClose | Handle -> IO () | |
hGetContents | Handle -> IO String | |
hputStrLn | Handle -> IO () | |
putStrLn | String -> IO () | |
stdout | Handle | |
System.IO.Error | userError | String -> IOError |
Text.ParserCombinators |
Control.Concurrrent.MVar
MVar problems due… race conditions forgotten locks deadlocks inconsistent lock ordering corruption uncaught exceptions lost wakeups ommited notifications - Control.Concurrent.Chan
- reads block until there is a value to read
- writes never block
non base
- https://haskell-containers.readthedocs.io/en/latest/
- time https://williamyaoh.com/posts/2019-09-16-time-cheatsheet.html
package | module | functions |
---|---|---|
array | Data.Array | |
containers | Data.Graph | |
Data.IntMap | ||
Data.IntSet | ||
Data.Map | ||
Data.Sequence | ||
Data.Set | ||
Data.Tree | ||
binary | Data.Binary | |
bytestring | Data.ByteString | efficiently dealing with files |
hPut :: Handle -> ByteString -> IO () | ||
hGetSome :: Handle -> Int -> IO ByteString | ||
null :: ByteString -> Bool | ||
pack :: [Word8] -> ByteString | ||
unpack :: ByteString -> [Word8] | ||
Data.ByteString.Lazy | fromStrict toStrict | |
Data.ByteString.Char8 | instead of Word8 | |
deepseq | Control.DeepSeq | |
directory | System.Directory | |
getHomeDirectory :: IO FilePath | ||
getCurrentDirectory :: IO FilePath | ||
setCurrentDirectory :: FilePath -> IO () | ||
getDirectoryContents :: FilePath -> IO [FilePath] | ||
getAppUserDataDirectory :: FilePath -> IO FilePath | ||
exceptions | Control.Monad.Catch | |
filepath | System.FilePath | |
System.OsPath | ||
System.OsString | ||
haskeline | System.Console | |
hoopl | Compiler.Hoopl | |
hpc | Trace.Hpc | |
integer-gmp | GHC.Integer.GMP | |
libiserv | ||
mtl | Control.Monad.Accum | |
Control.Monad.Cont | ||
Control.Monad.Except | ||
Control.Monad.Identity | ||
Control.Monad.RWS | ||
Control.Monad.Reader | ||
Control.Monad.Select | ||
Control.Monad.State | ||
Control.Monad.Trans | ||
Control.Monad.Writer | ||
network | Network.Socket | socket :: Family -> SocketType -> ProtocolNumber -> IO Socket |
getAddrInfo :: Maybe AddrInfo -> Maybe HostName -> Maybe ServiceName -> IO [AddrInfo] | ||
tupleToHostAddress :: (Word8,Word8,Word8,Word8) -> HostAddress | ||
connect :: Socket -> SockAddr -> IO () | ||
gracefulClose :: Socket -> Int -> IO () | ||
setSocketOption :: Socket -> SocketOption -> Int -> IO () | ||
Network.Socket.ByteString | ||
sendAll :: Socket -> ByteString -> IO () | ||
recv :: Socket -> Int -> IO ByteString | ||
parsec | Text.Parsec | |
Text.ParserCombinators.Parsec | ||
pretty | Text.PrettyPrint | |
process | DEPRECATED | |
System.Process | ||
shell :: String -> CreateProcess | ||
proc :: FilePath -> [String] -> CreateProcess | ||
createProcess :: CreateProcess -> IO (Maybe Handle, MH, MH, ProcessHandle) | ||
sync | callProcess :: FilePath -> [String] -> IO () | |
sync | callCommand :: String -> IO () | |
async | spawnProcess :: FilePath -> [String] -> IO ProcessHandle | |
async | spawnCommand :: String -> IO ProcessHandle | |
(deprecated) | rawSystem :: String -> [String] -> IO GHC.IO.Exception.ExitCode | |
(deprecated) | system :: String -> IO ExitCode | |
terminfo | System.Console.Terminfo | |
template-haskell | Language.Haskell.TH | |
text | Data.Text | efficient/strict String unicode++ |
pack :: String -> Text | ||
unpack :: Text -> String | ||
hGetChunk :: Handle -> IO Text | ||
hGetLine | ||
null :: Text -> Bool | ||
uncons :: Text -> Maybe (Char, Text) | ||
unsnoc :: Text -> Maybe (Text, Char) | ||
snoc :: Text -> Char -> Text | ||
cons :: Char -> Text -> Text | ||
Data.Text.IO | hPutStrLn :: Handle -> Text -> IO () | |
Data.Text.Encoding | d/encodeUtf8 - to/from ByteString | |
time | Data.Time | formatTime :: FormatTime t => TimeLocale -> String -> t -> String |
parseTimeM :: (MF m, TL t) => Bool -> TimeLocale -> String -> String -> m t | ||
utcToLocalTime :: TimeZone -> UTCTime -> LocalTime | ||
utcToZonedTime :: TimeZone -> UTCTime -> ZonedTime | ||
utctDay :: UTCTime -> Day | ||
toGregorian :: Day -> (Integer, Int, Int) | ||
defaultTimeLocale :: TimeLocale | ||
getCurrentTimeZone :: TimeZone | ||
getCurrentTime :: UTCTime | ||
UTCTime = point in time, utc | ||
Day = point in time, local in days | ||
LocalTime = point in time, local in picoseconds | ||
NominalDiffTime = time interval, utc | ||
CalendarDiffDays = time interval, local in days | ||
CalendarDiffTime = time interval, local in picoseconds | ||
transformers | Control.Monad.Trans | |
stm | transactional memory (optimistic acquisition, pessimist commit) | |
Control.Concurrent.STM | ||
Control.Concurrent.STM.TVar | aka Transactional Variable | |
newTVar :: a -> STM (TVar a) | ||
readTVar :: TVar a -> STM a | ||
writeTVar :: TVar a -> a -> STM () | ||
modifyTVar :: TVar a -> (a -> a) -> STM () | ||
modifyTVar' :: TVar a -> (a -> a) -> STM () | ||
Control.Monad.STM | atomically :: STM a -> IO a | |
orElse :: STM a -> STM a -> STM a | ||
check :: Bool -> STM () | ||
retry :: STM a | ||
throwSTM :: Exception e => e -> STM a | ||
catchSTM :: Exception e => STM a -> (e -> STM a) -> STM a | ||
unix | System.Posix | |
xhtml | Text.XHtml |
- stm
- STM type is abstract
- STM actions cannot be interleaved with IO actions
typeclasses
- Type Variable http://jackkelly.name/blog/archives/2024/10/12/a_dictionary_of_single-letter_variable_names/
- a,b,c,d = is the free-variable
- e = for environment
- m = monad
- f = function
- A type can have at most ONE instance of a typeclass.
- In Haskell, a
Monad
must be a unary type constructor.- aka kind of "* -> *"
- https://www.adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html#monads
- https://wiki.haskell.org/All_About_Monads
- https://learnyouahaskell.com/a-fistful-of-monads
lift(s)
liftM (aka monadic fmap, bind??)
Control.Monad
liftM :: Monad m => (a -> b) -> m a -> m b
liftIO -
Control.Monad.IO.Class
class (Monad m) => MonadIO m where -- aka any Monad that an IO can be lifted INTO liftIO :: IO a -> m a
liftA2 -
Control.Applicative
- apply a function between several functor values
- aka takes a normal binary function and promotes it to a function that operates on two applicatives
liftA2 :: (Applicative f) => (a -> b -> c) -> (f a -> f b -> f c) liftA2 f a b = f <$> a <*> b
do
- When to use (>>=) and when use do?
- if it seems like you're writing way Too Many Lambdas use
do
- Too many variables that get introduced on one line, only to get used on the next, use (>>=)
Or use both
do x1 <- a1 >>= f1 >>= f2 x2 <- a2 >>= f3 >>= f4 f5 x1 x2
- if it seems like you're writing way Too Many Lambdas use
Shipped
MINIMAL | description | extras | |
---|---|---|---|
Foldable | foldr foldMap | data structure that can be folded | foldr foldl null length sum product maximum minim elem |
Show | show | conversion of values to readable String's | |
Eq | (==) (=/) | equality and inequality | |
Ord | compare (<=) | max min < > <= >= | |
Enum | toEnum, fromEnum | can be enumerated by the Int value | [Foo..Bar] |
Bounded | minBound, maxBound | with minimum and maximum bounds | |
Functor | fmap (<$>) | can be mapped over | |
Semigroup | (<>) | associative binary op | sconcat stimes |
Monoid | mempty | associative binary op with identity | mconcat mappend (<>) |
Applicative | pure (<*>) | a functor, sequence and combine ops | |
Alternative | empty (<¦>) | returns the first one that doesn "fail" | |
Monad | bind (>>=) | do (=<<) | |
IsString | fromString | OverloadedStrings implicitly runs it | - |
IsString
defined in Data.StringShow
- exists for the sake of GHCi and for testing, not for real use in applications
- we recommend never allowing the behavior of your program to depend on the
show
function
definitions
class Eq a where (==) :: a -> a -> Bool class Monoid a where mempty :: a -- neutral element mappend :: a -> a -> a -- associative binary operation mconcat :: [a] -> a class Semigroup a where (<>) :: a -> a -> a class Semigroup a => Monoid a where ... -- since GHC 8.4 class Functor f where fmap :: (a -> b) -> f a -> f b class (Functor f) => Applicative f where -- class constraint pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b -- (ME: apply a wrapped function to a wrapped value) class Foldable t where foldMap :: Monoid m => (a -> m) -> t a -> m foldr :: (a -> b -> b) -> b -> t a -> b fold :: Monoid m => t m -> m foldr' :: (a -> b -> b) -> b -> t a -> b foldl :: (a -> b -> a) -> a -> t b -> a foldl' :: (a -> b -> a) -> a -> t b -> a foldr1 :: (a -> a -> a) -> t a -> a foldl1 :: (a -> a -> a) -> t a -> a class Monad m where -- 🪠 (>>=) :: m a -> (a -> m b) -> m b -- (ME: apply a function that returns a wrapped value to a wrapped value) class IsString a where fromString :: String -> a class Applicative f => Alternative f where -- Control.Alternative empty :: f a -- a computation with zero results (<|>) :: f a -> f a -> f a -- combines two computations, returns the first "successful" one (it "recovers" from failure) class Monad m => MonadPlus m where mzero :: a -- equivalent to empty mplus :: m a -> m a -> m a -- equivalent to mplus
Declaring
class Eq a where -- name=Eq - type_variable=a -- posible class constraint goes here, after class, before => (==), (/=) :: a -> a -> Bool -- they share the same signature {-# INLINE (/=) #-} -- GHC pragma to define inline methods? {-# INLINE (==) #-} x /= y = not (x == y) -- default implementation x == y = not (x /= y) {-# MINIMAL (==) | (/=) #-} -- minimal complete definition, either
Codebases
- coreutils in haskell https://github.com/Gandalf-/coreutils/
- hclip (multiplatform lib) https://hackage.haskell.org/package/Hclip-3.0.0.4/docs/src/System-Hclip.html#setClipboard
- clipboard manager https://github.com/erebe/greenclip/
- https://lotz84.github.io/haskellbyexample/
- 30:00 Haskell The Legend of DSLs - Alejandro Serrano | ZuriHac 2022 https://www.youtube.com/watch?v=kdkWhtpX1BA
- Haskell Adventures in IO - Alejandro Serrano | ZuriHac 2022 https://www.youtube.com/watch?v=Gt6OeWxkcEI
- Sonic 2 https://www.youtube.com/playlist?list=PLly9WMAVMrazvDoyEu9rM7v5IZJ6Hp91u
- https://learn-haskell.blog/
- https://howistart.org/posts/haskell/1/
- Silly job interview questions in Haskell https://chrispenner.ca/posts/interview
- Beating C with 80 lines of Haskell: wc
- article https://chrispenner.ca/posts/wc
- source https://github.com/ChrisPenner/wc
- TODO: concurrency…
- https://wiki.haskell.org/Implement_a_chat_server
- https://wiki.haskell.org/Roll_your_own_IRC_bot
- http://stefan.saasen.me/articles/git-clone-in-haskell-from-the-bottom-up/
- https://github.com/jwiegley/git-all/blob/master/Main.hs
- shell like library https://github.com/luke-clifton/shh
- https://github.com/omelkonian/AlgoRhythm (music)
- window manager https://github.com/xmonad/xmonad
- exercises https://github.com/effectfully-ou/haskell-challenges
- https://github.com/jappeace/cut-the-crap/ ffmpeg based, cut video silences
- A Haskell library that simplifies access to remote data, such as databases or web-based services.
- source https://github.com/facebook/Haxl
- they created ApplicativeDo extension
- 2012 game https://github.com/nikki-and-the-robots/nikki
- dead game studio https://github.com/keera-studios
Snippets
yes
https://theory.stanford.edu/~blynn/c2go/
import Control.Monad import System.Environment main :: IO () main = getArgs >>= forever . putStrLn . f where f [] = "y" f xs = unwords xs
Definition of forever on Control.Monad (possibly)
forever :: IO () -> IO () forever a = a >> forever a -- OR forever a = do a; forever a
reading a file + system + aeson
https://haskell-works.github.io/posts/2018-07-25-problem-of-parsing-large-datasets.html
import Control.Monad import Data.Aeson import GHC.Stats import System.Posix.Process import System.Process import qualified Data.ByteString.Lazy as BS import qualified System.Environment as IO main :: IO () main = do pid <- getProcessID (filename:_) <- IO.getArgs bs <- BS.readFile filename let !maybeJson = decode bs :: Maybe Value system $ "ps aux | grep " <> show pid <> " | grep -v grep" forM_ maybeJson $ \_ -> putStrLn "Done"