evilsoft/crocks

Unwrap Pair with two Maybes

janczer opened this issue ยท 4 comments

Can you help me please. I'm trying to refactor my code and I'm stuck with unwrap Pair.

Here is my code:

const code = 'aabbc'; // valid litera code
// const code = '1231231233'; // valid numerical code
// const code = '123123aaaaa'; // invalid code

const isNumberCode = code => !!/^[0-9]{10}$/.exec(code);
const isLiteralCode = code => !!/^[A-Za-z]{5}$/.exec(code);

// flow :: a -> Pair a a
const flow = code => Pair(code, code)

const numberJust = code => Just({id: code})
const literalJust = code => Just({serial: code})
const isNumberCodeMaybe = ifElse(isNumberCode, numberJust, Nothing)
const isLiteralCodeMaybe = ifElse(isLiteralCode, literalJust, Nothing)

const result = 
    flow(code)
        .bimap(isNumberCodeMaybe, isLiteralCodeMaybe)
// here I want unwrap the result

I want write the function that merge or unwrap the Pair:

// Pair Just Nothing -> Just
// Pair Nothing Just -> Just
// Pair Nothing Nothing -> Nothing

Can you help me please?

Hey, what you're looking for is merge and alt. merge will take a function that expects two arguments which will be both sides of the Pair. If we pass in the Maybe's pointfree function alt we'll get the behaviour you're chasing

import { Maybe, Pair, merge, alt, map } from 'crocks'
const { Just, Nothing } = Maybe

const unwrap = merge(alt)

unwrap(Pair(Just('something'), Nothing()))
//=> Just "something"

unwrap(Pair(Nothing(), Just('something')))
//=> Just "something"

unwrap(Pair(Nothing(), Nothing()))
//=> Just "something"

There are a few improvements we can make to your code, i'll throw up an example in a bit

So this is probably not the best put it removes the need for Pair and the potential confusion when looking at the code

import { Maybe, Pair, merge, alt, map, ifElse, fanout, when, objOf, constant, or, unless } from 'crocks'

const { Just, Nothing } = Maybe

// const code = 'aabbc'; // valid litera code
// const code = '1231231233'; // valid numerical code
const code = '123123aaaaa'; // invalid code

const testOn = regex => code => RegExp(regex).test(code)

const isNumberCode = testOn(/^[0-9]{10}$/);
const isLiteralCode = testOn(/^[A-Za-z]{5}$/);

Just(code)
  .map(unless(or(isNumberCode, isLiteralCode), Nothing))
  .map(when(isNumberCode, objOf('id')))
  .map(when(isLiteralCode, objOf('serial')))

Thank you! Your improved code looks very good!

I'm glad you like it, let us know if you have any other questions