Fp-ts: Convert Either to Validation

Created on 13 May 2017  路  5Comments  路  Source: gcanti/fp-ts

Is it possible to write a function that converts an Either to a Validation?

I presume this would only work if the Left type was a semigroup, as that is required by Validation?

Here was my attempt, however it fails to compile:

import { StaticSemigroup } from "fp-ts/lib/Semigroup";

const eitherToValidation = <L, A>(
    either: either.Either<StaticSemigroup<L>, A>,
): validation.Validation<L, A> => {
    return either
        .fold(
            leftSemigroup => (
                validation.failure<L, A>([], leftSemigroup)
            ),
            right => validation.success<L, A>(right),
        );
};

Most helpful comment

I'd also be curious to know why io-ts uses Either and not Validation?

That's a good question!

Either, having a monad instance, is strictly more powerful than Validation. You lose the ability to run validations in parallel but you gain the chainability of validations. There are many validations which can't be parallelized, for example integers

  • first you must check that the input is a number
  • then you must check that the number is an integer

That "then" requires the power of a monad and its chain function

import { left, right } from 'fp-ts/lib/Either'

// any -> number
const isNumber = (input: any) => typeof input === 'number' ? right<string, number>(input) : left<string, number>('Not a number')

// number -> integer
const isNumberInteger = (input: number) => input % 1 === 0 ? right<string, number>(input) : left<string, number>('Not an integer')

// now I can compose the validations

// any -> integer
const isInteger = (input: any) => isNumber(input).chain(isNumberInteger)

console.log(isInteger('s')) // Left("Not a number")
console.log(isInteger(1.1)) // Left("Not an integer")
console.log(isInteger(1)) // Right(1)

I used the term "compose" because monads are a way to make composable a group of functions which naturally don't compose. Those functions, called Kleisli arrows, have the following general signature

A -> M<B>
b -> M<C>

where M is a type constructor (kind * -> *). In case of Either we get (its left type is not important for what we are saying)

any -> Either<number>
number -> Either<integer>

From this point of view monads are pretty easy to explain: under the hood is just function composition (well to be precise is morphism composition).

This is a repo where I try to explain all these things (I put up a functional programming meet up here in Milano and the repo contains a series of lectures I gave during the last months)

Alas is in italian..

https://github.com/gcanti/functional-programming

All 5 comments

For context, I am using io-ts which returns an Either type, but I have a function that needs to return Validation.

I'd also be curious to know why io-ts uses Either and not Validation? :-)

@OliverJAsh
Try something like that (not tested)

const eitherToValidation = <L, A>(
  leftSemigroup: StaticSemigroup<L>,
  either: either.Either<L, A>,
): validation.Validation<L, A> =>
  either.fold(
    left => validation.failure<L, A>(leftSemigroup, left),
    right => validation.success<L, A>(right),
  )

Usage (with array):

eitherToValidation(array, either.left([10]))

@OliverJAsh
You may use that one, it's more specific (force the usage of array) but may be handy.

const eitherToValidation = <L,A>(
  either: either.Either<L, A>,
): validation.Validation<L[], A> =>
  either.fold(
    left => validation.failure<L[], A>(array, [left]),
    right => validation.success<L[], A>(right),
  )

Usage

eitherToValidation(either.left(10))

I'd also be curious to know why io-ts uses Either and not Validation?

That's a good question!

Either, having a monad instance, is strictly more powerful than Validation. You lose the ability to run validations in parallel but you gain the chainability of validations. There are many validations which can't be parallelized, for example integers

  • first you must check that the input is a number
  • then you must check that the number is an integer

That "then" requires the power of a monad and its chain function

import { left, right } from 'fp-ts/lib/Either'

// any -> number
const isNumber = (input: any) => typeof input === 'number' ? right<string, number>(input) : left<string, number>('Not a number')

// number -> integer
const isNumberInteger = (input: number) => input % 1 === 0 ? right<string, number>(input) : left<string, number>('Not an integer')

// now I can compose the validations

// any -> integer
const isInteger = (input: any) => isNumber(input).chain(isNumberInteger)

console.log(isInteger('s')) // Left("Not a number")
console.log(isInteger(1.1)) // Left("Not an integer")
console.log(isInteger(1)) // Right(1)

I used the term "compose" because monads are a way to make composable a group of functions which naturally don't compose. Those functions, called Kleisli arrows, have the following general signature

A -> M<B>
b -> M<C>

where M is a type constructor (kind * -> *). In case of Either we get (its left type is not important for what we are saying)

any -> Either<number>
number -> Either<integer>

From this point of view monads are pretty easy to explain: under the hood is just function composition (well to be precise is morphism composition).

This is a repo where I try to explain all these things (I put up a functional programming meet up here in Milano and the repo contains a series of lectures I gave during the last months)

Alas is in italian..

https://github.com/gcanti/functional-programming

Super useful and insightful replies. Thank you! :-)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vicrac picture vicrac  路  4Comments

steida picture steida  路  4Comments

mmkal picture mmkal  路  3Comments

mattgrande picture mattgrande  路  3Comments

amaurymartiny picture amaurymartiny  路  4Comments