Skip to content

Instantly share code, notes, and snippets.

@choonkeat
choonkeat / AWS.elm
Last active August 1, 2020 03:55
"Signing AWS requests with Signature Version 4" in Elm https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
module AWS exposing (Config, HttpRequest, Service(..), httpTask, sign__)
import Base16
import Crypto.HMAC
import Crypto.Hash
import DateFormat
import Http
import Json.Encode
import Task exposing (Task)
import Time
{-| Maybe like how data from remote server can be modelled with 4 states `krisajenkins/remotedata`
perhaps form input can be modelled similarly too, giving us a convenient way to work with them
`err` stores validation errors for the form values, e.g. Dict String String
`a` stores the raw value from user input, e.g. Dict String String
`b` is the data type that we expect to wield if `a` is valid, e.g. API.CreateUser.Input
-}
type FormData err a b
= NotValid a err
@choonkeat
choonkeat / CmdWorkerPool.elm
Last active May 31, 2020 14:11
Module that allows Elm app to execute N `Cmd` in parallel (queue the remaining `Cmd`), when one is done execute the next Cmd in queue
module CmdWorkerPool exposing (Request, State, init, request, update)
import Task exposing (Task)
{-| State
- workersLimit limits the maximum number of concurrent Cmd
- workersCount tracks the current number of Cmd in progress
- backlog stores a List of Cmd that are waiting to be dispatched
npm init --yes
npm install --save elm elm-live
elm init
@choonkeat
choonkeat / explicit-better-than-implicit.md
Last active March 6, 2020 16:50
"Explicit is better than implicit." Python said it first, but Python didn't say much

the init function in Go

If you're unfamiliar with it, here's a short paragraph

package mylib

func init() {
    defaultClient = new(42)
}
type fataler interface {
Fatal(...interface{})
}
func logJSON(t fataler, w io.Writer, label string, callback func() (interface{}, error)) {
data, err := callback()
if err != nil {
t.Fatal(err, label)
}
# Put your entry point make targets above this line
# Put build targets that are NOT meant to be entry points
# inside a different file. This way, when invoking shell
# autocomplete with `make <tab>`, only the targets in the
# main `Makefile` will be listed as options
include Makefile.libs
# make target for files are usually intentional

TLDR: you have to find the underlying context of the advice; when is it good for what. when you have your own reasons to adopt, then you'll also know when to let go (not wait for someone else to disband the party)

Don't just blindly follow the advice of "experts", take it with a grain of salt.

is prudent advice regarding following advice... but not enough; it's just varying the level of trust. Instead of only adjusting trust % level on what people tell you, try it out. for real or thought experiment on your past projects.

e.g. coming from years of writing Ruby to writing Go, i was accustomed to plucking the values out from os.Getenv wherever I needed it; there's a certain "plug and play" to doing things this way. chuyeow's PR reviews kept pointing out that cli flags are preferred and that it's ok to pass them in through function arguments to where I needed to use them. Though I didn't agree with the practice, nor could I see why it would be good in Go context, I went with it to see how things will pan

A note about "type signature" and "type variables"

convert : Exchange from to -> Currency from -> Currency to

from and to are type variables to ensure things line up.

They are not variables in the regular sense: we cannot use from or to in our function body to + or do anything with. Actually, in our function body, there is no variable from or to

I realise you could more or less guess how the first argument relates to the next arguments for certain functions was it because you've used those functions before so you remember or because it's actually guessable?

TLDR: you can tell from the function signature, but we're not used to it coming from another language

Example Json.Decode.map2

map2 : (a -> b -> value) -> Decoder a -> Decoder b -> Decoder value