Skip to content

Instantly share code, notes, and snippets.

View benkolera's full-sized avatar

Ben Kolera benkolera

  • biza.io
  • Brisbane, Australia
View GitHub Profile
@benkolera
benkolera / kakfinder.nix
Created August 16, 2019 23:07
Finds all of the .kak files in a directory like what plug.kak does.
{ nixpkgs ? import <nixpkgs> {} }:
with nixpkgs.lib; with builtins;
let
gosub = (parents: subpath: type:
let path = "${parents}/${subpath}";
in
if type == "directory"
then allKakFiles path
else if type == "regular" && hasSuffix ".kak" subpath then [path]
else []
@benkolera
benkolera / monad_transformers.md
Last active June 29, 2019 07:23
Motivation for MonadTransformers, Mtl Constraints and How that Ties to EventWriterT / EventWriter in reflex

Note: This article requires you to understand basic haskell syntax, typeclasses and Functor/Applicative/Monad already. If you don't already understand these, this may be a struggle to understand.


Nested Monads aren't very fun

When writing monadic code, we can get ourselves into awkward circumstances where we have monads inside monads. Take for instance this code:

data OurErrors = OutputFileAlreadyExists | ParseFailure deriving (Eq, Show)
frontend :: Frontend (R FrontendRoute)
frontend = Frontend
{ _frontend_head = el "title" $ text "Obelisk Minimal Example"
, _frontend_body = prerender_ blank $ do
i <- inputElement def
t <- throttle 2 (_inputElement_input i)
d <- debounce 2 (_inputElement_input i)
tD <- holdDyn "" t
dD <- holdDyn "" d
text "throttled("

Our web applications are getting increasingly more complicated. They are becoming more distributed and increasingly powered by combinations of complex, constantly changing and large datasets. All while users are increasingly more connected and want the latest information instantly without any slow page loads or stale information.

To address this, developers have turned to layers of caching and single page applications so that there are layers of aggregated and preloaded state as close to the user as possible, to be immediately available when it is requested. This comes at a high cost: it is very difficult to invalidate or update those caches when the upstream information changes. This is especially problematic when the stale caches can accidentally cause real bugs rather than show stale data to users.

The big issue here is that we're not just caching expensive-to-compute static data. We are caching data that changes over time. There are a number of architectual patterns that can be applied, but to date, n

@benkolera
benkolera / gist:126d563251cd31f989a3ef166192dc1f
Created June 16, 2019 05:36
matrix-builder nix-shell one liner
nix-shell -p '(import <nixos-1903> {}).pkgs.haskell.compiler.ghcjs84' -p 'haskell.packages.ghc864.ghcWithPackages(ps: [ps.zlib ps.HsOpenSSL])' -p cabal-install -p pkg-config -p brotli -p zlib -p zlib.dev -p postgresql -p openssl -p haskellPackages.happy
diff --git a/src-ui.v3/src/API.hs b/src-ui.v3/src/API.hs
index d93e209..cae595d 100644
--- a/src-ui.v3/src/API.hs
+++ b/src-ui.v3/src/API.hs
@@ -7,6 +7,7 @@
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
-- {-# LANGUAGE PolyKinds #-}
getV2IdxStates' :: Event t () -> m (Event t (ReqResult () PkgIdxTs))
getV2Info' :: Event t () -> m (Event t (ReqResult () ControllerInfo))
getV2Packages' :: Event t () -> m (Event t (ReqResult () (Vector PkgN)))
getV2PackagesHistory' :: Dynamic t (QParam PkgIdxTs) -> Dynamic t (QParam PkgIdxTs) -> Event t () -> m (Event t (ReqResult () (Vector IdxHistoryEntry)))
getV2PackageHistory' :: Dynamic t (Either Text PkgN) -> Event t () -> m (Event t (ReqResult () (Vector PkgHistoryEntry)))
getV2PackageReports' :: Dynamic t (Either Text PkgN) -> Event t () -> m (Event t (ReqResult () (Set PkgIdxTs)))
getV2PackageReportSummary' :: Dynamic t (Either Text PkgN) -> Dynamic t (Either Text PkgIdxTs) -> Event t () -> m (Event t (ReqResult () PkgIdxTsReport))
getV2PackageReportDetail' :: Dynamic t (Either Text PkgN) -> Dynamic t (Either Text PkgIdxTs) -> Dynamic t (Either Text Ver) -> Dynamic t (Either Text CompilerID) -> Event t () -> m (Event t (ReqResult () CellReportDetail))
getV2PackageTags' :: Dynamic t (Either Text Pk
@benkolera
benkolera / gist:7d56bc389f905a93abe8604f277125cb
Created April 23, 2019 21:00
Results from my docker image.
Error: Found a project at ., but had to traverse one or more insecure directories to get there:
.obelisk/impl
.obelisk
.
Please ensure that all of these directories are owned by you and are not writable by anyone else.
unpacking 'https://github.com/NixOS/nixpkgs/archive/2d656a9729739e8ca5486058a76669d0ea4442df.tar.gz'...
copying path '/nix/store/s22136cyrw0lghy59m8bjkjkgar0cf3n-cabal2nix-backend' from 'https://nixcache.reflex-frp.org'...
copying path '/nix/store/4nbcjv2z4qham9jxp4q5d72yj1r32vh4-cabal2nix-common' from 'https://nixcache.reflex-frp.org'...
@benkolera
benkolera / Obelisk.Servant.hs
Created April 7, 2019 23:02
Hacky way to get a servant app on an obelisk route.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
module Obelisk.Servant where
import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar)
import Data.Bifunctor (bimap)
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}