This now lives on GitHub: https://github.com/friedbrice/runhs
-- ghcid -c'stack repl --resolver nightly --package time' haskell-time.hs --allow-eval | |
---- | |
-- # Haskell Time Crib Sheet | |
---- | |
-- Excellent sources for this small guide include: | |
-- | |
-- * https://two-wrongs.com/haskell-time-library-tutorial.html | |
-- * https://williamyaoh.com/posts/2019-09-16-time-cheatsheet.html |
- Put
ci.yaml
into.github/workflows/
- Follow https://github.com/cachix/cachix-action#usage to setup Cachix and benefit from quick CI build times.
Option<T> |
non-Option (T | undefined ) |
|
---|---|---|
accessing property | userOption.map(user => user.age) |
userNullish?.age |
calling a method | userOption.map(user => user.fn()) |
userNullish?.fn() |
providing fallback | ageOption.getOrElse(0) |
ageNullish ?? 0 |
filter | ageOption.filter(checkIsOddNumber) |
`ageNull |
This gist demonstrates a trick I came up with which is defining
IsString
for Q (TExp a)
, where a
is lift
-able. This allows you
to write $$("...")
and have the string parsed at compile-time.
On GHC 9, you are able to write $$"..."
instead.
This offers a light-weight way to enforce compile-time constraints. It's
basically OverloadedStrings
with static checks. The inferred return type
I've been fiddling about with an idea lately, looking at how higher-kinded types can be represented in such a way that we can reason with them in Rust here and now, without having to wait a couple years for what would be a significant change to the language and compiler.
There have been multiple discussions on introducing higher-ranked polymorphism into Rust, using Haskell-style Higher-Kinded Types (HKTs) or Scala-looking Generalised Associated Types (GATs). The benefit of higher-ranked polymorphism is to allow higher-level, richer abstractions and pattern expression than just the rank-1 polymorphism we have today.
As an example, currently we can express this type:
{-# LANGUAGE ScopedTypeVariables #-} | |
{-# LANGUAGE TypeApplications #-} | |
{-# LANGUAGE FlexibleContexts #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE DeriveGeneric #-} | |
module GenericMonoid where | |
import Data.Monoid | |
import Data.Maybe |
{-# LANGUAGE ConstraintKinds #-} | |
{-# LANGUAGE DataKinds #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE FunctionalDependencies #-} | |
{-# LANGUAGE GADTs #-} | |
{-# LANGUAGE GeneralizedNewtypeDeriving #-} | |
{-# LANGUAGE InstanceSigs #-} | |
{-# LANGUAGE LambdaCase #-} | |
{-# LANGUAGE NoImplicitPrelude #-} | |
{-# LANGUAGE NoMonomorphismRestriction #-} |
import org.scalacheck.cats.implicits._ | |
import org.scalacheck.Gen | |
import io.circe.{Decoder, Encoder} | |
object Test extends App { | |
case class X(i: Int) | |
implicit val x: Encoder[X] = Wrapper[X].deriveInstance[Encoder] | |
implicit val y: Decoder[X] = Wrapper[X].deriveInstance[Decoder].withErrorMessage("some custom error msg") | |
val z: Gen[X] = Wrapper[X].lift(Gen.choose(0, 10)) |
{- TODO: The Num and Fractional instances don't implement all methods. | |
- In practice this is fine but for completeness they should be done. | |
-} | |
{-# LANGUAGE FlexibleContexts #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE TypeFamilies #-} | |
module NumericLits where | |
data I = I | |
i :: I |