Categories
Web Development

A (recursive!) function present Lara is proud of

Having fun with recursion, pattern matching, and logical equivalence.

Of course, future Lara will look back at this and think, “Wow, so basic”, and past Lara would have been like “WTF is that”. Present Lara, however, is proud of this function and slowly, very slowly, developing an intuition for rEcUrSiOn.

Present Lara is also quite uncomfortable writing about herself in the third person like this…and will stop now.

Here is the function:

export const tt = ( p, str, q ) => {
  switch ( str ) {
    case 'and':
      return p && q;
    case 'or':
      return p || q;
    case 'implies':
      return ( p === true && q === false ) ? false : true;
    case 'xor':
      return tt( 
        tt( p, 'or', q ),
        'and',
        ! tt( p, 'and', q ) 
      );
    case 'iff':
      return tt(
        tt( p, 'implies', q ),
        'and',
        tt( q, 'implies', p )
      );
    default:
      break;
  }
};

I’ve been learning about pattern matching in this Programming Languages class on Coursera and it’s so good. The class in in Standard ML (usually referred to as ML), a functional language that, as far as I know, is more popular in academic circles than industry circles. I’ve started and stopped the course a few times, and I think that’s been really helpful in letting the concepts sink in.

The above function is in JavaScript, not ML. When it’s called, as you can see in the above 'xor' and 'iff' cases, is like a little language for logical equivalence (also known as propositional logic, statement logic, and/or boolean logic – I’m not sure yet which is the appropriate term). I wonder if the use of p’s and q’s in logical statements is how the expression “mind your p’s and q’s” originated. I have called the function / language tt, for truth table. You can read about truth tables here.

And here are the test cases for the tt function/baby language, which amount to truth tables!

describe( 'truth table - tt', () => {
   it( 'should evaluate or', () => {
     expect( tt( false, 'or', true ) ).toBe( true );
     expect( tt( true, 'or', false ) ).toBe( true );
     expect( tt( false, 'or', false ) ).toBe( false );
     expect( tt( true, 'or', true ) ).toBe( true );
   });

   it( 'should evaluate and', () => {
     expect( tt( true, 'and', true ) ).toBe( true );
     expect( tt( false, 'and', true ) ).toBe( false );
     expect( tt( true, 'and', false ) ).toBe( false );
     expect( tt( false, 'and', false ) ).toBe( false );
   });

   it( 'should evaluate xor', () => {
     expect( tt( false, 'xor', true ) ).toBe( true );
     expect( tt( true, 'xor', false ) ).toBe( true );
     expect( tt( true, 'xor', true ) ).toBe( false );
     expect( tt( false, 'xor', false ) ).toBe( false );
   });

   it( 'should evaluate implies', () => {
     expect( tt( true, 'implies', false ) ).toBe( false );
     expect( tt( false, 'implies', true ) ).toBe( true );
     expect( tt( false, 'implies', false ) ).toBe( true );
     expect( tt( true, 'implies', true ) ).toBe( true );
   } );

   it( 'should evaluate iff', () => {
     expect( tt( true, 'iff', false ) ).toBe( false );
     expect( tt( false, 'iff', true ) ).toBe( false );
     expect( tt( true, 'iff', true ) ).toBe( true );
     expect( tt( false, 'iff', false ) ).toBe( true );
   } );
 });