title: Hyperfunctions, Breadth-First Traversals, and Search author: Oisín Kidney patat: theme: codeBlock: [vividBlack] code: [vividBlack] incrementalLists: true eval: ruby:
| {- | |
| See https://www.reddit.com/r/haskell/comments/q1oyws/dependency_injection_using_a_recordoffunctions | |
| for full context | |
| -} | |
| {-# LANGUAGE RecordWildCards #-} | |
| {-# LANGUAGE DeriveGeneric #-} |
| liftType :: forall t. Typeable t => Q Type | |
| liftType = do | |
| let rep = typeRep @t | |
| go rep | |
| where | |
| go :: forall (a :: k). TypeRep a -> Q Type | |
| go tr = | |
| case tr of | |
| Con tyCon -> do | |
| let |
| {-# LANGUAGE LinearTypes #-} | |
| {-# LANGUAGE LambdaCase #-} | |
| {-# LANGUAGE BlockArguments #-} | |
| {-# LANGUAGE NoImplicitPrelude #-} | |
| {-# LANGUAGE QualifiedDo #-} | |
| import Prelude.Linear hiding (partition) | |
| import qualified Control.Functor.Linear as Linear | |
| import Control.Functor.Linear (State, state, execState, pure) | |
| import qualified Data.Array.Mutable.Linear as Array |
| {-# Language RankNTypes #-} | |
| {-# Language PolyKinds #-} | |
| {-# Language DataKinds #-} | |
| {-# Language PatternSynonyms #-} | |
| {-# Language ViewPatterns #-} | |
| {-# Language RoleAnnotations #-} | |
| {-# Language StandaloneKindSignatures #-} | |
| {-# Language TypeFamilies #-} | |
| {-# Language TypeOperators #-} | |
| {-# Language GADTs #-} |
Most data serialization formats, like JSON, YAML, and EDN, feature a similar set of basic building blocks, namely:
- Some primitive values, like numbers, strings, and booleans;
- Key-value pairs, also known as maps, dictionaries, or objects;
- Sequences, usually in the form of lists or arrays, and sometimes also sets.
I completely agree with the fact that those are basic building blocks for data inside any information system. However, as a Haskeller I always miss one additional part of my toolbox: variants. Variants are essentially tagged values which contain further values inside.
| {-# LANGUAGE | |
| PolyKinds | |
| , RankNTypes | |
| , TypeFamilies | |
| , TypeOperators | |
| , TypeApplications | |
| , FlexibleInstances | |
| , ScopedTypeVariables | |
| , AllowAmbiguousTypes | |
| , MultiParamTypeClasses |
Updated version can be found on my website.
Given the following haskell script generate-random-samples.hs that requires mwc-random ...
{-# LANGUAGE ScopedTypeVariables #-}
import System.Random.MWCMonads and delimited control are very closely related, so it isn’t too hard to understand them in terms of one another. From a monadic point of view, the big idea is that if you have the computation m >>= f, then f is m’s continuation. It’s the function that is called with m’s result to continue execution after m returns.
If you have a long chain of binds, the continuation is just the composition of all of them. So, for example, if you have
m >>= f >>= g >>= hthen the continuation of m is f >=> g >=> h. Likewise, the continuation of m >>= f is g >=> h.
Do not get bogged down in microoptimizations before you've assessed any macro optimizations that are available. IO and the choice of algorithm dominate any low level changes you may make. In the end you have to think hard about your code!
Before starting to optimize:
- Is the -O2 flag on ?
- Profile: which part of the code is the slow one.
- Use the best algorithm in that part.
- Optimize: implement it in the most efficient way.