show char
: For a c :: Char
, use [c] :: String
ˡInt
vs Integer
:
Int
: fixed precisionInteger
: arbitrary precisionWord
: 'an unsigned integral type, with the same size as Int' - Haskell language report 2010 ˡInt
Bounds can be seen for instances of Bounded
type class:
> minBound :: Int
λ-9223372036854775808
> maxBound :: Int
λ9223372036854775807
> maxBound :: Bool
λTrue
> minBound :: Bool
λFalse
> maxBound :: Word
λ18446744073709551615
> maxBound :: Float
λ<interactive>:5:1: error:
No instance for (Bounded Float) arising from a use of ‘maxBound’
• In the expression: maxBound :: Float
• In an equation for ‘it’: it = maxBound :: Float
> maxBound :: Integer
λ<interactive>:6:1: error:
No instance for (Bounded Integer)
• of ‘maxBound’
arising from a use In the expression: maxBound :: Integer
• In an equation for ‘it’: it = maxBound :: Integer
Beyonds bounds, value will wrap around:
λ> (maxBound :: Int) + 1
-9223372036854775808
~
showing up in a type annoation indicates that two types are equivalent. It is a type constraint that haskell would need to be able to solve inorder for the code to type check.
Eg (from a use of megaparsec):
atom :: (Token s ~ Char, MonadParsec e s m) => m (Token s)
= satisfy isUpper atom
<$> |
fmap |
Functor f => (a -> b) -> f a -> f b |
<*> |
(apply) | Applicative f => f (a -> b) -> f a -> f b |
>>= |
(bind) | Monad m => m a -> (a -> m b) -> m b |
<$ |
Functor f => a -> f b -> f a |
|
<│> |
(alternative) | Alternative f => f a -> f a -> f b |
<* |
Applicative f => f a -> f b -> f a |
|
*> |
Applicative f => f a -> f b -> f b |
|
>> |
?? | Monad m => m a -> m b -> m b |
>< |
?? | |
<> |
?? | Semigroup a => a -> a -> a |
. |
(compose) | (b -> c) -> (a -> b) -> (a -> c) |
$ |
(a -> b) -> a -> b |
(>>)
a >> b
is similar to a >>= b
except that the value produced from a
is ignored. ᵈ
Kind of like:
a >>= b |
a >> b |
---|---|
do | do |
x <- a | a |
b | b |
Similar to *>
as evident from type.
(<>)
Associative operator associated with a semigroup ᵈ ᵈ. ᵈ
In the case of list:
> [1,2] <> [3]
λ1,2,3] [
because list is an instance of Semigroup
:
λ> :i []
type [] :: * -> *
data [] a = [] | a : [a]
-- Defined in `GHC.Types'
instance Alternative [] -- Defined in `GHC.Base'
instance Applicative [] -- Defined in `GHC.Base'
instance Eq a => Eq [a] -- Defined in `GHC.Classes'
instance Functor [] -- Defined in `GHC.Base'
instance Monad [] -- Defined in `GHC.Base'
instance Monoid [a] -- Defined in `GHC.Base'
instance Ord a => Ord [a] -- Defined in `GHC.Classes'
instance Semigroup [a] -- Defined in `GHC.Base'
instance Show a => Show [a] -- Defined in `GHC.Show'
instance Foldable [] -- Defined in `Data.Foldable'
instance Read a => Read [a] -- Defined in `GHC.Read'
instance MonadFail [] -- Defined in `Control.Monad.Fail'
instance Traversable [] -- Defined in `Data.Traversable'
<$
Kinda like:
> :t (<$)
λ(<$) :: Functor f => a -> f b -> f a
> (<$) 3 [4]
λ3]
[
> (<$) 3 [3]
λ3]
[
> (<$) True [False]
λTrue]
[
> (<$) True (Just False)
λJust True
Also see:
From the first link:
f <$> parser
means that you need to parse something and then applyf
to the result.
a <$ parser
means that you don't need to parse anything (you're not interested in the result) - you only need to recognize, which can be much faster.
.
g . f
≡ g (f x)
(.) :: (b -> c) -> (a -> b) -> (a -> c)
<*
and *>
, <<
<*
feels like 'ensure RHS is there but return LHS'*>
is the other direction.>>
: like *>
but for monads> :t (<*)
λ(<*) :: Applicative f => f a -> f b -> f a
> (<*) (Just True) (Just False)
λJust True
> (*>) (Just True) (Just False)
λJust False
---
> :t (>>)
λ(>>) :: Monad m => m a -> m b -> m b
> (>>) (Just True) (Just False)
λJust False
Constructors can be made infix too. Just start its name with a :
.
Example:
data Re = Atom
| Re :- Re -- Concat
infixr 6 :-
—
Precedence: Higher the number, higher the precednece.
Built-in stuff:
infixl 9 !!
infixr 9 .
infixr 8 ^
infixl 7 *
infix 7 /, `div`, `quot`, `rem`, `mod`
infixl 6 +, -
infix 5 \\
infixr 5 ++, :
infix 4 ==, /=, <, <=, >=, >
infix 4 `elem`, `notElem`
infixr 3 &&
infixr 2 ||
infixr 0 $
—
See:
Similar to the one in Python.
> chars = ['a'..'e']
> [char | char <- chars]
"abcde"
Or with multiple lists like
> let chars = ['a'..'c']
> let nums = [1..4]
> [(char, num) | char <- chars, num <- nums]
[('a',1),('a',2),('a',3),('a',4),('b',1),('b',2),('b',3),('b',4),('c',1),(
'c',2),('c',3),('c',4)]
Get first element.
> head [1..3]
1
Get everything except the first element.
> tail [1..3]
[2,3]
Get ('takes') the first n
number of elements from the argument list
> take 2 ['a'..'e']
"ab"
Create a new list from lst
, dropping the first n
elements.
> drop 6 [1..10]
[7,8,9,10]
sum <lst>
Add all elements of the list.
> sum [1..3]
6
product <list>
Find the product of all elements of the list.
> product [1..3]
6
span <condition> <list>
span :: (a -> Bool) -> [a] -> ([a], [a])
{-
(a -> Bool) is the condition; which is in effect a function
returning a Bool.
-}
Splits input list into two parts.
Returns a tuple of two lists.
Takes elements from the list, and returns it as the first output list, as long as condition is true. Remaining elements, including the one for which the conditon became false, will be placed in the second output list.
Example:
> span (/='a') "helloaworld"
("hello","awo")
length <list>
length :: Foldable t => t a -> Int
Returns the length of argument list.
> length "hello"
5
> length [3,4]
2
elem <element> <list>
Example:
> elem 'a' "ab"
True
> elem 'c' "ab"
False
notElem <element> <list>
Opposite of Elem
.
> notElem 'a' "ab"
False
> notElem 'c' "ab"
True
Indexing starts from 0
.
> [0,1,2,3] !! 2
2
> "abcdef" !! 1
'b'
> "abc"!!3
*** Exception: !!: index too large
Proxy
import Data.Proxy
Prelude Data.Proxy> :i Proxy
type role Proxy phantom
data Proxy (t :: k) = Proxy
https://downloads.haskell.org/~ghc/7.8.4/docs/html/users_guide/roles.html#:~:text=The%20role%20of%20a%20type,as%20T%20Int%20Bool%20c%20).
3 possible roles:
type role Set nominal
type role Ptr representational
type role
can be used by the compiler to ensure that no type promises are broken.
Example of use nominal
type role: https://downloads.haskell.org/~ghc/7.8.4/docs/html/users_guide/roles.html
As another example, we can consider a type Set a that represents a set of data, ordered according to a's Ord instance. While it wouldnnn generally be type-safe to consider a to beat role representational, it is possible that a newtype and its base type have different orderings encoded in their respective Ord instances. This would lead to misbehavior at runtime. So, the author of the Set datatype would like its parameter to be at role nominal. This would be done with a declaration
Role annotations can't be done for type synonyms (ie, those declared with type
). But is possible for newtype
I guess.
I guess:
phantom
--
type role T3 _ nominal
data T3 a b = MkT3 a
-- role of a is left for ghc to infer (by underscore)
-- b is phantom here. nominal was unnecessary. but it won't cause error. just unnecessarily strict??
From #haskell:
15:48 < int-e> Yes, this is about restricting coercions. To coerce T a to T b, if the argument has a nominal role, a and be must be the same; if it's representational, then a and b must be coercible, and if it's a phantom argument, then you can coerce no matter what the types a and b are.
Doubts:
https://downloads.haskell.org/~ghc/7.4.1/docs/html/users_guide/equality-constraints.html#:~:text=where%20we%20require%20that%20the,rank%20types%20are%20otherwise%20enabled
Syntax where you see stuff like (a ~ b)
type role Set nominal
, where Set
has kind * -> *
, prevents coercion of Set a
to Set b
. (Doubt: Even when a
and b
are same??)
Coercion is possible when the compiler is sure that the two types have the same representation. https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Coerce.html
See: Zero-cost coercions for Haskell - ICFP 2014 by Breitner, Eisenberg, Jones, Weirich https://www.seas.upenn.edu/~sweirich/papers/coercible-JFP.pdf
Apparently, some definitions related to those from Data.Coerce
: https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-Type-Coercion.html
Data.Tagged
: Related to Proxy
type?
_|_
in haskell documentation (for ⊥
)https://downloads.haskell.org/~ghc/7.0.3/docs/html/users_guide/pragmas.html
INLINE
, NOINLINE
: Control inlining of function definitions
{-# INLINE myfun #-}
INLINABLE
: Suggest inlining while still leaving the final decision to the compiler.ANN
: AnnotateLooks like this is for passing options that could be passed down to ghc command.
Eg: Disable a specific warning throughout a file:
-- For 'warning: [-Wpartial-type-signatures]'
{-# OPTIONS_GHC -fno-warn-partial-type-signatures #-}
RULES
pragmaRULES
pragma use also possible#-}
should start in a column to the right of the opening {-#
'-fenable-rewrite-rules
(disabled by -fno-enable-rewrite-rules
)
ghc -O
implies -fenable-rewrite-rules
forall
forall
quantified variablesSyntax:
rule-name [phase-control-number] rewrite-equation
Exampleˢ:
{-# RULES
"map/map" forall f g xs. map f (map g xs) = map (f.g) xs
#-}
RULES
optimization needs be active => can't be used from ghci ʳSee:
Use HeapSize
module.
λ> runHeapsize 30 $ recursiveSizeNF (1::Int)
Just 7
λ> runHeapsize 30 $ recursiveSizeNF True
Just 7
λ> runHeapsize 30 $ recursiveSizeNF (True, False)
Just 36
λ> runHeapsize 30 $ recursiveSizeNF (Left True :: Either Bool Bool)
Just 33
https://hackage.haskell.org/package/heapsize-0.3.0.1/docs/HeapSize.html
Read
instance for a classhttp://dev.stephendiehl.com/hask/
For interactive haskell REPL.
Command | Short | Description |
---|---|---|
:reload | :r | Code reload |
:type | :t | Type inspection |
:kind | :k | Kind inspection |
:info | :i | Information (can show definiton with constructors) |
:p | Print the expression | |
:edit | :e | Load file in system editor |
:load | :l | Set the active Main module in the REPL |
:module | :m | Add modules to imports |
:add | :ad | Load a file into the REPL namespace |
:instances | :in | Show instances of a typeclass |
:browse | :bro | Browse all available symbols in the REPL namespace |
Needs Data.List
.
Prelude> import Data.List
Prelude Data.List> [1,2,3] \\ [2]
[1,3]
<?>
: parser <?> err_msg
err_msg
shown when parsing with parser
failsSeq
(as in list) type from Data.Sequence
of 'containers' package.
<│ |
Add element to left end of a seq | a -> Seq a -> Seq a |
│> |
Add element to right end of a seq | a -> Seq a -> Seq a |
>< |
Concatenate two sequnces | Seq a -> Seq a -> Seq a |
<+>
: Vertical split<=>
: Horizontal splitTimers can be made with BChan
More:
https://hackage.haskell.org/package/lens-tutorial-1.0.5/docs/Control-Lens-Tutorial.html
^.
val^.attr.subattr
is like obj.attr.subattr
in Pythonval ^. (attr . subattr)
^.
is same as view
: x ^. l = view l x
lens
: lot of dependenciesmicrolens
or lens-simple
: light-weight form of lens
with fewer dependencies—
%=
:
>>> execState (do _1 %= f;_2 %= g) (a,b)
(f a, g b)
>>> execState (do both %= f) (a,b)
(f a, f b)
.=
:
>>> execState (do _1 .= c;_2 %= d) (a,b)
(c, d)
>>> execState (do both %= c) (a,b)
(c, c)
—
More concepts:
Functions: re, unto, set, .=,
One possible use of lens: getters-setters when using nested record types
over
: setterview
: getterIt's like this:
data Lens a b = Lens
view :: a -> b
{ over :: (b -> b) -> (a -> a)
, }
Create lens for a type with:
makeLenses ''<bigtype>
makeLenses ''<smalltype>
This is made possible with TemplateHaskell.
Field names in the record type should have underscore prefix.
KnownNat
Suppose we need this:
foo :: KnownNat n => Vec n Bool -> Vec n Bool
= repeat False foo v
but without KnownNat
. repeat
needs KnownNat
.
ie, aim is like this:
{-# LANGUAGE PartialTypeSignatures #-}
foo :: Vec _ Bool -> Vec _ Bool
= (repeat False) :: (typeOf v) foo v
Exploit this fact: 'Functor doesn't need KnownNat
' (thanks to Rowan Goemans).
foo :: Vec _ Bool -> Vec _ Bool
= fmap (const False) v foo v
—
> (const False) <$> [0,1]
λFalse,False]
[
> fmap (fmap (const False)) [[0,1], [2,3]]
λFalse,False],[False,False]]
[[
> (const False <$>) <$> [[0,1], [2,3]]
λFalse,False],[False,False]] [[
cabal.project
file is needed if there are multiple sub-packages within the packages, each with a distinct .cabal
fileGHCUP_INSTALL_BASE_PREFIX=<path>
(From here.)
Following function won't type check.
f :: [a] -> [a]
= ys ++ ys
f xs where ys :: [a]
= reverse xs ys
This is because the a
in f
and the one in ys
are not considered the same. This function is same as:
f :: [a] -> [a]
= ys ++ ys
f xs where ys :: [b]
= reverse xs ys
Meaning can be made clear to compiler by having a universal quantification over a
.
{-# LANGUAGE ScopedTypeVariables #-}
f :: forall a. [a] -> [a]
= ys ++ ys
f xs where ys :: [a]
= reverse xs ys
With the forall
, the type variable bound by a
ranges throughout the entire defintion of f
. This way, haskell would know that the a
used in both locations are the same.
The same function could be written without forall
as well. Using a pattern type signature like thisʳ:
{-# LANGUAGE ScopedTypeVariables #-}
f :: [a] -> [a]
xs :: [aa]) = ys ++ ys
f (where ys :: [aa]
= reverse xs ys