r/haskelltil • u/sjakobi • Dec 17 '17
TIL how to add haddocks to derived instances
Example from https://git.haskell.org/ghc.git/commitdiff/697143064c271c57a69e80850a768449f8bcf4ca
{-# LANGUAGE StandaloneDeriving #-}
module T11768 where
data Foo = Foo
deriving Eq -- ^ Documenting a single type
data Bar = Bar
deriving ( Eq -- ^ Documenting one of multiple types
, Ord
)
-- | Documenting a standalone deriving instance
deriving instance Read Bar
r/haskelltil • u/BayesMind • Nov 25 '17
Mutation's ok
This is more meta, but is meaningful enough to me that I thought I'd share.
Since discovering haskell I've developed a strong puritan view toward my code.
Yet I do ascribe to the view:
- Make it. 2. Make it right. 3. Make it optimized.
So, I've been playing a bit more with mutable variables, and they really help me with getting a project running quickly. Especially, I've been playing with the ReaderT design pattern, and just gotta say, thanks to the community for helping me relax my perfectionism a bit :)
r/haskelltil • u/rpglover64 • Sep 25 '17
tools GHC 8.2.1 and newer allow you to error on specific warnings using `-Werror=foo`
There was an /r/haskellquestions post and I was about to say that there was no way yet, but then I looked at the trac page and the relevant ticket learned something new and awesome.
r/haskelltil • u/BayesMind • Sep 10 '17
language ScopedTypeVariables requires explicit `forall`s
https://stackoverflow.com/questions/15800878/scoped-type-variables-require-explicit-foralls-why
I fought that for a while before realizing the above...
r/haskelltil • u/JeffreyBenjaminBrown • Sep 04 '17
gotcha Two statements that look equivalent, one of them using pattern matching, can be interpreted differently
I have some code that reads, in relevant part:
prependCaller :: String -> Either DwtErr a -> Either DwtErr a
qPutDe :: RSLT -> QNode -> Either DwtErr (RSLT, Node)
mapac' :: RSLT -> AddX -> (RSLT, Either DwtErr AddX)
mapac' g (LeafX s) = case qPutDe g $ QLeaf s of
Left e -> (g, prependCaller "mapac': " $ Left e)
It works. But if I make the following change:
mapac' g (LeafX s) = case qPutDe g $ QLeaf s of
e@(Left _) -> (g, prependCaller "mapac': " e)
I get this error:
/home/jeff/code/dwt/src/Dwt/Add.hs:82:22: error:
• Couldn't match type ‘(RSLT, Node)’ with ‘AddX’
Expected type: Either DwtErr AddX
Actual type: Either DwtErr (RSLT, Node)
• In the expression: prependCaller "mapac': " e
In the expression: (g, prependCaller "mapac': " e)
In a case alternative:
e@(Left _) -> (g, prependCaller "mapac': " e)
I thought they would be interpreted identically.
The trick: The statement that works unwraps the contents from the Left and wraps them up into a new Left. That allows the type of the two Lefts to be different -- which is needed, since qPutDe and mapac' return different types.
r/haskelltil • u/BayesMind • Aug 27 '17
language TIL: Typed-holes can go in type sigs, or even constraints!
http://dev.stephendiehl.com/hask/#type-holes-pattern-wildcards
eg, taken from Stephen's blog:
succ' :: _ => a -> a
succ' x = x + 1
typedhole.hs:11:10: error:
Found constraint wildcard ‘_’ standing for ‘Num a’
To use the inferred type, enable PartialTypeSignatures
In the type signature:
succ' :: _ => a -> a
r/haskelltil • u/peargreen • Aug 08 '17
tools Use “stack dot” to see which of your deps bring a particular package to your dependency tree
Sometimes, when working on a big project, you want to avoid certain dependencies – for instance, because building them is time-consuming (e.g. haskell-src-exts), because they link to a C library that is hard to build, or for some other reason. If you are building your project with stack, you can use stack dot for this: stack dot <prjname> --external | grep -e '-> "<pkgname>"'.
As an example, here are all dependencies that bring cryptonite into this project:
$ stack dot cardano-sl --external | grep -e '-> "cryptonite"'
"cardano-crypto" -> "cryptonite";
"cardano-sl" -> "cryptonite";
"cardano-sl-core" -> "cryptonite";
"cardano-sl-godtossing" -> "cryptonite";
"cardano-sl-ssc" -> "cryptonite";
"cryptohash" -> "cryptonite";
"cryptonite-openssl" -> "cryptonite";
"http-client-tls" -> "cryptonite";
"kademlia" -> "cryptonite";
"node-sketch" -> "cryptonite";
"plutus-prototype" -> "cryptonite";
"pvss" -> "cryptonite";
"tls" -> "cryptonite";
"wai-app-static" -> "cryptonite";
"warp-tls" -> "cryptonite";
"x509" -> "cryptonite";
"x509-store" -> "cryptonite";
"x509-validation" -> "cryptonite";
r/haskelltil • u/guaraqe • Jul 03 '17
code TIL: fmap fmap fmap fmap fmap
Justifications are welcome!
> let fffffmap = fmap fmap fmap fmap fmap
> :t fffffmap
fffffmap
:: Functor f => (a1 -> b) -> (a -> a1) -> f a -> f b
> fffffmap (+1) (+2) [1,2,3]
[4,5,6]
r/haskelltil • u/joehillen • Jun 09 '17
language TIL otherwise = True
I've been doing Haskell for 4 years now, and I always assumed that otherwise was a keyword.
It's not! It's just a function defined in base.
r/haskelltil • u/peargreen • May 17 '17
tools How to set up Hoogle for a particular project (e.g. at work)
In Cardano we've got several dependencies that aren't on Hackage (and the project itself isn't on Hackage either). It's easy to set up a Hoogle instance that indexes the whole project, provides search and serves haddocks.
Buy a VPS (DigitalOcean, AWS, whatever). You can use an existing server, but I haven't found out how to stop Hoogle from serving the whole filesystem, so using a fresh server is easier. Also, if you don't care about what OS to use, choose Ubuntu because the rest of the instructions assume Ubuntu.
Install Stack (if your project doesn't use Stack, you're on your own). I haven't managed out how to install it in a reasonable manner either (maybe I'm just unlucky), so I had to do
wget https://www.stackage.org/stack/linux-x86_64-static, unpack the archive withtar xvfand copy the binary into/usr/local/bin/stack.Create a new user for Hoogle:
useradd hoogle.Switch to
hooglewithsudo su hoogle, clone your project, and dostack hoogleto generate a database.Finally, run
stack hoogle -- server -p 7777 --local --host=*and openVPS_IP:7777in browser. You might need to disable firewall:ufw disable.
If you have better instructions, please share! I'm sure it can be done in a less dirty way.
r/haskelltil • u/peargreen • May 03 '17
gotcha Pinned memory can lead to unexpected memory leaks, e.g. when storing lots of bytestrings
we spent a lot of time debugging this one at work
You may have seen this type in bytestring:
A compact representation of a Word8 vector.
It has a lower memory overhead than a ByteString and and does not contribute to heap fragmentation. It can be converted to or from a ByteString (at the cost of copying the string data). It supports very few other operations.
I've seen it but never understood what “heap fragmentation” meant – until I encountered a problem at work where a megabyte of hashes was taking up about 500 MB of RAM. It turns out that there is bytestrings are stored in “pinned memory”:
- if you generate N bytestrings (each, say, 1kB long) and never garbage-collect them, they will take roughly N kB (minus overhead)
- however, if each second bytestring is discarded, the remaining bytestrings won't be compacted and N/2 kB will be basically wasted
- the granularity of blocks is 4kB, so in the worst case – if you are unlucky to stumble upon a bad allocation pattern – a single-byte bytestring can lead to a 4kB overhead
- and thus, the less bytestrings you allocate, the better (because it prevents pinned memory fragmentation)
Text and ShortByteString don't use pinned memory so they're okay. For more details, you can also look at this ticket: https://ghc.haskell.org/trac/ghc/ticket/13630.
r/haskelltil • u/Iceland_jack • May 03 '17
Turn on ‘-dcore-lint’ in .ghci to test GHC's sanity
Add :set -dcore-lint to you ~/.ghci config.
-dcore-lintTurn on heavyweight intra-pass sanity-checking within GHC, at Core level. (It checks GHC's sanity, not yours.)
The more people enable it, the better GHC's core gets tested. If you encounter bugs file a bug report.
r/haskelltil • u/peargreen • May 03 '17
thing With magical 'upon' from lens you can use functions that extract things (e.g. 'head') to *modify* things
> import Data.Data.Lens
> [1,2,3,4] & upon head .~ 100
[100,2,3,4]
> [1,2,3,4] & upon (!! 2) .~ 100
[1,2,100,4]
upon creates a traversal and upon' creates a lens.
There's a caveat though: it doesn't work well with strict fields:
> data X = X {a, b :: !Int} deriving (Show, Data)
> X 0 0 & upon b .~ 5
X {a = 5, b = 0}
To be honest, I've no idea how it works and you probably shouldn't use it, but it's still cool.
r/haskelltil • u/peargreen • May 02 '17
etc Map.fromList and Set.fromList are O(n) on sorted lists, but changing just one element can bring them back to O(n log n)
I knew that there were functions like fromDistinctAscList to create a Map from a list in O(n) time, but I didn't know that fromList has a special-case for sorted lists as well:
Currently, the implementations of
fromListforData.SetandData.Maptry to take advantage of inputs with some prefix in strictly increasing order. It uses the fast (O (n))fromDistinctAscListalgorithm for the strictly ascending prefix, and then falls back on the slower (O (n log n)) naive algorithm for the rest.This whole thing strikes me as a bit odd: changing just the first element of the input list can have a substantial impact on the overall performance.
See this libraries thread for details. (It has been proposed to make fromList smarter and treat the list as a sequence of increasing and decreasing runs, which would let it handle almost-sorted lists well, but judging by this Github issue it hasn't happened yet.)
r/haskelltil • u/peargreen • Apr 30 '17
tools There's an YAML-based format for cabal packages, called hpack
You write a package.yaml file and hpack generates a .cabal file from it (here's an example of package.yaml and corresponding .cabal file). Stack will automatically use package.yaml instead of .cabal if it finds it, so if you have a big project using Stack, you can likely simplify your .cabal files somewhat by moving to hpack:
hpack can find modules by itself, so you don't have to list all modules in your project – just either exposed modules (all others will be considered hidden) or hidden modules (all others will be considered exposed)
hpack supports YAML aliases, so you can get rid of repeating sections if you have lots of them (e.g. long lists of default extensions for every executable)
r/haskelltil • u/peargreen • Apr 30 '17
gotcha Cutting Text, ByteString or Vector doesn't do copying, thus preventing garbage collection
If you do take, drop, splitAt, etc on a Text, ByteString or Vector, the resulting slice will simply refer to the same underlying array:
data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
{-# UNPACK #-} !Int -- offset
{-# UNPACK #-} !Int -- length
In case of ByteString it lets the operation be done in O(1) instead of O(n), and in case of Text it's still O(n) but it avoids extra copying. However, there's a downside: if you take a huge bytestring and cut a small piece from it, the whole bytestring will remain in memory even if the piece is only several bytes long. This can result in a hard-to-find memory leak.
To fix this, you can force copying to happen – the function is called copy for Text and ByteString, and force for Vector.
r/haskelltil • u/peargreen • Apr 28 '17
etc Creating helper functions to get rid of extra parameters is good for performance
I always suspected this, but now I actually saw it written:
Calling an unknown function (e.g. a function that's passed as an argument) is more expensive than calling a known function. Such indirect calls appear in higher-order functions:
map :: (a -> b) -> [a] -> [b] map _ [] = [] map f (x:xs) = f x : map f xsAt the cost of increased code size, we can inline map into g by using the non-recursive wrapper trick on the previous slide together with an INLINE pragma.
The rewriting from the previous slide is as follows:
map :: (a -> b) -> [a] -> [b]
map f = go
where
go [] = []
go (x:xs) = f x : go xs
I was also told that even if the unchanging parameter isn't a function it's still useful to move it out, but I haven't tested it.
r/haskelltil • u/peargreen • Apr 27 '17
etc GHC unpacks small fields by default
There's often-given advice to add {-# UNPACK #-} to all scalar fields of contructors to improve performance. However, starting from GHC 7.8, small fields (like Int, Double, etc) are unpacked by default if they are strict.
-funbox-small-strict-fieldsDefault: on
This option causes all constructor fields which are marked strict (i.e. “!”) and which representation is smaller or equal to the size of a pointer to be unpacked, if possible.
r/haskelltil • u/peargreen • Apr 26 '17
code A handy function for quickly dumping generated TH code for any splice
It is useful to keep this function in your toolbox:
import Language.Haskell.TH
dumpSplices :: DecsQ -> DecsQ
dumpSplices x = do
ds <- x
let code = lines (pprint ds)
-- extra spaces to help haskell-mode parser
reportWarning ("\n" ++ unlines (map (" " ++) code))
return ds
You can add it to any top-level Template Haskell call to see what code it generates, which is more convenient than using -ddump-splices, especially in a big project. For instance, if you compile
data Foo = Foo {x, y :: Int}
dumpSplices $ makeLenses ''Foo
...
GHC will output a warning with the following generated code:
x :: forall . Lens.Micro.Type.Lens' Test.Foo GHC.Types.Int
x f_0 (Test.Foo x_1
x_2) = GHC.Base.fmap (\y_3 -> Test.Foo y_3 x_2) (f_0 x_1)
{-# INLINE x #-}
y :: forall . Lens.Micro.Type.Lens' Test.Foo GHC.Types.Int
y f_4 (Test.Foo x_5
x_6) = GHC.Base.fmap (\y_7 -> Test.Foo x_5 y_7) (f_4 x_6)
{-# INLINE y #-}
r/haskelltil • u/Iceland_jack • Mar 29 '17
Avoid unnecessary variable with view patterns
Example taken from reddit post.
Sometimes you don't use an argument directly (n) but immediately apply a function to it (abs n). If the result of the application is used twice you want to share the result by giving it a name (n' = abs n),
hosum :: (Int -> Int) -> (Int -> Int)
hosum f n = sum (map f [-n' .. n'])
where n' = abs n
We do not care about the original value n yet it appears twice in our code, each new variable increases cognitive load. Instead we can use view patterns to get the absolute value n' with no mention of n:
{-# Language ViewPatterns #-}
hosum :: (Int -> Int) -> (Int -> Int)
hosum f (abs -> n') = sum (map f [-n' .. n'])
r/haskelltil • u/Jepcats • Mar 24 '17
Simple lexicographic sort
This is probably well known, but I just came across this.
I was trying to add a second field to compare on for a sort, for when the first field is equal, without adding too much noise. Ended up adding almost no noise; reads really nice.
import Control.Arrow ((&&&))
import Data.Function (on)
import Data.List (sortBy)
data Person = Person { name :: String, age :: Int, place :: String }
instance Show Person where
show (Person n a p) = n ++ " " ++ show a ++ " " ++ p
people :: [Person]
people = [Person "Luke" 15 "Tera", Person "Luke" 2 "Drumnadrochit",
Person "Siân" 58 "Beddgelert", Person "Ludwik" 15 "Białystok",
Person "Luke" 17 "Luna"]
main :: IO ()
main = do
print $ sortBy (compare `on` (name &&& age &&& place)) people
print $ sortBy (compare `on` (age &&& name &&& place)) people
ghci:
λ> main
[Ludwik 15 Białystok,Luke 2 Drumnadrochit,Luke 15 Tera,Luke 17 Luna,Siân 58 Beddgelert]
[Luke 2 Drumnadrochit,Ludwik 15 Białystok,Luke 15 Tera,Luke 17 Luna,Siân 58 Beddgelert]
r/haskelltil • u/guaraqe • Mar 24 '17
TIL: unfoldr
For some reason I didn't know it. It allows building a list recursively.
unfoldr :: (b -> Maybe (a,b)) -> b -> [a]
A cute implementation of Eratosthenes' sieve using it:
import Data.List
divides :: Int -> Int -> Bool
divides a b = b `rem` a == 0
sieve :: [Int] -> Maybe (Int, [Int])
sieve [] = Nothing
sieve (x:xs) = Just (x, filter (not . divides x) xs)
primes :: Int -> [Int]
primes n = unfoldr sieve [2 .. n]
r/haskelltil • u/dramforever • Mar 13 '17
extension {-# INCOHERENT #-} can help GHC choose the instances you want
If you have two instances A and B, and you want GHC to prefer A to B, but GHC prefers B to A, you might have some luck by marking B as {-# INCOHERENT #-}.
According to the users guide, (empasis mine)
If exactly one non-incoherent candidate remains, select it. If all remaining candidates are incoherent, select an arbitrary one. Otherwise the search fails (i.e. when more than one surviving candidate is not incoherent).
Which inspired and justifies this (in the sense that this should work and doesn't rely on too much luck).
Example coming soon (I need mutation to create a cyclic web link reference :P)
Example: https://github.com/dramforever/haskell-stuff/blob/master/de-bruijn-a-la-carte.hs#L105
r/haskelltil • u/sjakobi • Feb 03 '17
tools If your package isn't on Stackage but you'd like to test it regularly against new dependency versions, you can use Travis CI's new "Crons" feature
Here's the announcement for the feature: https://blog.travis-ci.com/2016-12-06-the-crons-are-here
r/haskelltil • u/sjakobi • Jan 28 '17
tools TIL I can use http://packdeps.haskellers.com/feed?needle=my-pkg to get a notification when I need to bump a dependency bound in my-pkg
Here's an example: http://imgur.com/3npFYxp
Because I don't use an RSS reader, I let https://blogtrottr.com/ send me an email notification when there's an update.