Experimenting with logical equivalence in JavaScript

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


This function 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):

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.

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/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 );
   } );
 });