Skip to content

Latest commit

 

History

History
251 lines (162 loc) · 7.53 KB

README.md

File metadata and controls

251 lines (162 loc) · 7.53 KB

Hope is postponed disappointment

Cover

These are the code snippets used during the talk "Hope is postponed disappointment".

To test the Elm code, you can either do it online following the links below, or running these commands to test them locally

git clone https://github.com/lucamug/hope.git
cd hope
npx elm reactor

Then you can browse the *.elm files from http://localhost:8000/

To test the TypeScript code, you can do it online following the links below.

Example 1

Elm code

Code on-line

module Main exposing (main)

import Html exposing (text)
import Json.Decode exposing (Error, decodeString, errorToString, field, map, string)


-- type Result error value = Ok value | Err error


type alias User =
    { name : String }


parseJSON : String -> Result Error User
parseJSON =
    field "name" string |> map User |> decodeString


json =
    "{ \"name\": \"John\" }"


result =
    parseJSON json


main =
    case result of
        Ok user ->
            text ("Hi " ++ user.name)

        Err error ->
            text ("Error: " ++ errorToString error)

TypeScript code

Code on-line

type Result <Err, Ok> = { kind: 'Ok'; value: Ok } | { kind: 'Err'; error: Err };

type User = { name: string };

function parseJSON (json: string | undefined): Result <string, User> {
  try {
    if (json === undefined) {
      return { kind: 'Err', error: 'JSON is undefined' };
    }
    const user = JSON.parse(json) as User;
    if (!user || !user.name) {
      return { kind: 'Err', error: '"name" key is missing' };
    }
    return { kind: 'Ok', value: user };
  } catch (error) {
    return { kind: 'Err', error: `Invalid JSON ${error}` };
  }
}

const json = '{ "name": "John" }';
const result = parseJSON(json);

switch (result.kind) {
  case 'Ok':
    console.log("Hi " + result.value.name);
    break;
  case 'Err':
    console.log("Error: " + result.error);
    break;
  default:
    const exhaustiveCheck: never = result;
    break;
}

Example 2

Using map and andThen to concatenate functions that may fail divideBy and not fail multiplyBy.

JavaScript Code

Code on-line

type Result<X, A> = { tag: 'Ok'; value: A } | { tag: 'Err'; error: X };

const divideBy = (a: number, b: number): Result<string, number> => {
  if (a === 0) {
    return { tag: 'Err', error: 'Divided by 0' };
  } else {
    return { tag: 'Ok', value: b / a };
  }
}

const multiplyBy = (a: number, b: number): number => {
  return a * b;
}

const map = <X, A, B>(callback: (value: A) => B, result: Result<X, A>): Result<X, B> => {
  switch (result.tag) {
    case 'Err': return { tag: 'Err', error: result.error };
    case 'Ok' : return { tag: 'Ok', value: callback(result.value) };
  }
}

const andThen = <X, A, B>(callback: (value: A) => Result<X, B>, result: Result<X, A>): Result<X, B> => {
  switch (result.tag) {
    case 'Err': return { tag: 'Err', error: result.error };
    case 'Ok' : return callback(result.value);
  }
}

// 9 / 3 * 10 / 5 * 2
const total = 
        map     ( res => multiplyBy (  2, res ),
        andThen ( res => divideBy   (  5, res ), 
        map     ( res => multiplyBy ( 10, res ), 
        andThen ( res => divideBy   (  3, res ),
    { tag: 'Ok', value: 9 } ))));

console.log(total);

// Logged value: { tag: 'Ok', value: 12 }

Example 3

Adding partial application.

Elm code

Code on-line

module Main exposing (main)

import Html exposing (text)
import Result exposing (andThen, map)

divideBy a b = if a == 0 then Err "Divided by 0" else Ok (b / a) 

multiplyBy a b = a * b

-- 9 / 3 * 10 / 5 * 2
total =
    Ok 9
        |> andThen ( divideBy    3 )
        |> map     ( multiplyBy 10 )
        |> andThen ( divideBy    5 )
        |> map     ( multiplyBy  2 )

main = text <| Debug.toString total

-- Logged value: Ok 12

TypeScript code

Code on-line

type Result<X, T> = { tag: 'Ok'; value: T } | { tag: 'Err'; error: X };

const map = <A, B>(callback: (value: A) => B) => (result: Result<string, A>): Result<string, B> => {
  switch (result.tag) {
    case 'Ok': return { tag: 'Ok', value: callback(result.value) };
    case 'Err': return result;
  }
};

const andThen = <A, B>(callback: (value: A) => Result<string, B>) => (result: Result<string, A>): Result<string, B> => {
  switch (result.tag) {
    case 'Ok': return callback(result.value);
    case 'Err': return result;
  }
};

const divideBy = (a: number) => (b: number): Result<string, number> => {
  if (a === 0) {
    return { tag: 'Err', error: 'Divided by 0' };
  } else {
    return { tag: 'Ok', value: b / a };
  }
};

const multiplyBy = (a: number) => (b: number): number => {
  return a * b;
}

// 9 / 3 * 10 / 5 * 2
const total = 
        map      ( multiplyBy (  2 ) )(
        andThen  ( divideBy   (  5 ) )(
        map      ( multiplyBy ( 10 ) )(
        andThen  ( divideBy   (  3 ) )(
    { tag: 'Ok', value: 9 }))));

console.log(total);

// Logged value: { tag: 'Ok', value: 12 }