This technique helps validate arbitrary conditions in deeply nested structures without writing additional code — with the help of Haskell Generics.
It boils down to this pattern:
<!-- | |
Created by Kuitos on 2015/03/06 10:15 AM. | |
Email: kuitos.lau@gmail.com | |
author: EdwardCTaylor | |
author: Kuitos | |
Licence: MIT | |
--> | |
<!DOCTYPE html> | |
<html> | |
<head> |
import { getParameterFromSsm } from 'aws-ssm.sdk' | |
function getParameterValue(name: string, defaultValue: string) { | |
return process.env[name] || getParameterFromSsm(name, defaultValue); | |
} | |
export class LazyParameter extends LazyValue<string> { | |
constructor(name: string, defaultValue?: string) { | |
super(async () => { | |
return getParameterValue(name, defaultValue); |
It’s folklore that if you’re summing a list of numbers, then you should always use strict foldl
. Is that really true though? foldr
is useful for lists when the function we use is lazy in its second argument. For (+) :: Int -> Int -> Int
this is tyically not the case, but in some sense that’s because Int
is “too strict”. An alternative representation of numbers is to represent them inductively. If we do this, sumation can be lazy, and foldr
can do things that foldl
simply can’t!
First, let’s define natural numbers inductively, and say how to add them:
data Nat = Zero | OnePlus Nat deriving Show
one :: Nat
// Adapted from http://code.slipthrough.net/2016/08/10/approximating-gadts-in-purescript/ | |
import { Kind, URIS } from 'fp-ts/lib/HKT' | |
import { URI } from 'fp-ts/lib/Identity' | |
import { identity } from 'fp-ts/lib/function' | |
// ------------------------------------------ | |
// Leibniz | |
// ------------------------------------------ |
type StringBool = "true"|"false";
interface AnyNumber { prev?: any, isZero: StringBool };
interface PositiveNumber { prev: any, isZero: "false" };
type IsZero<TNumber extends AnyNumber> = TNumber["isZero"];
type Next<TNumber extends AnyNumber> = { prev: TNumber, isZero: "false" };
type Prev<TNumber extends PositiveNumber> = TNumber["prev"];
Monads 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 >>= h
then the continuation of m
is f >=> g >=> h
. Likewise, the continuation of m >>= f
is g >=> h
.
See also List of materials about Software Design in Haskell
Junior | Middle | Senior | Architect | |
---|---|---|---|---|
Haskell level | Basic Haskell | Intermediate Haskell | Advanced Haskell | Language-agnostic |
Haskell knowledge scope | Learn you a Haskell | Get programming with Haskell | Haskell in Depth | Knows several languages from different categories |
Get programming with Haskell | Haskell in Depth | Functional Design and Architecture | ||
[Other books on Software Engineering in Haskell](https://github.com/graninas/software-design-in-haskell#B |
sudo rm -rfv /Library/Caches/com.apple.iconservices.store; sudo find /private/var/folders/ \( -name com.apple.dock.iconcache -or -name com.apple.iconservices \) -exec rm -rfv {} \; ; sleep 3;sudo touch /Applications/* ; killall Dock; killall Finder |