Logika wyrażeń w instrukcjach warunkowych

Logika matematyczna to jedna z bardziej przydatnych w programowaniu (i ogólnie informatyce) dziedzin matematyki. Dzięki prawom logiki działają wszystkie układy elektroniczne. W codzienności programisty może przydać się zwłaszcza podczas optymalizacji warunków logicznych.

Przykładowo, inspekcja kodu Ruby w środowisko IntelliJ za błąd uważa sterowanie przepływem za pomocą negatywnego warunku typu: if !condition ... . Taki pojedynczy warunek wystarczy w takim przypadku zamienić na: unless condition .... W przypadku bardziej rozbudowanych warunków przydają się znane z liceum prawa de Morgana.

I prawo de Morgana (zaprzeczenia koniunkcji)
~(p ^ q) <==> (~p v ~q)

Poniższy kod sprawdza, czy jest widoczny nagłówek. Nagłówek powinien mieć tytuł oraz podtytuł. Jeżeli obydwa tytuły są widoczne, uznajemy ze jest wyświetlony poprawnie. I tak następujące instrukcje warunkowe:

if !is_title_displayed || !is_subtitle_displayed
  puts 'Header not visible!'
end

można zamienić na:

unless (is_title_displayed && is_subtitle_displayed)
  puts 'Header not visible!'
end

Zobaczmy, jak to działa.

def check(p, q)
  if !p || !q
    puts 'Header not visible!'
  else
    puts 'Header is displayed.'
  end
end

def check_morgan(p, q)
  unless p && q
    puts 'Header not visible!'
  else
    puts 'Header is displayed.'
  end
end

Test, czy obydwie funkcje są sobie równoważne:

is_title_displayed=true
is_subtitle_displayed=true
check(is_title_displayed,is_subtitle_displayed)
=> Header is displayed.
check_morgan(is_title_displayed,is_subtitle_displayed)
=> Header is displayed.

is_title_displayed=true
is_subtitle_displayed=false
check(is_title_displayed,is_subtitle_displayed)
=> Header not visible!
check_morgan(is_title_displayed,is_subtitle_displayed)
=> Header not visible!

is_title_displayed=false
is_subtitle_displayed=true
check(is_title_displayed,is_subtitle_displayed)
=> Header not visible!
check_morgan(is_title_displayed,is_subtitle_displayed)
=> Header not visible!

is_title_displayed=false
is_subtitle_displayed=false
check(is_title_displayed,is_subtitle_displayed)
=> Header not visible!
check_morgan(is_title_displayed,is_subtitle_displayed)
=> Header not visible!

Obydwie metody zachowują się identycznie.

II prawo de Morgana (zaprzeczenia alternatywy)
~(p v q) <==> (~p ^ ~q)

Poniższy kod zwraca wartość true, gdy linia zawiera jakieś znaki i nie zawiera napisu "Serial number".

def validate(line)
  if !line.empty? && !line.include?('Serial Number')
    puts 'True'
  else
    puts 'False'
  end
end  

def validate_morgan(line)
  unless(line.empty? || line.include?('Serial Number'))
    puts 'True'
  else
    puts 'False'
  end
end

Oczywiście funkcje te można zapisać w krótszej formie, ale dla celu artykułu pozostawiam formę rozwiniętą, gdzie lepiej widać, do się dzieje.

Czas na sprawdzenie poprawności…

Prawidłowa linia:

line='QWERTY'
validate(line)
=> True
validate_morgan(line)
=> True

Nieprawidłowe linie:

line=''
validate(line)
=> False
validate_morgan(line)
=> False

line='Serial Number'
validate(line)
=> False
validate_morgan(line)
=> False

Funkcje są sobie równoważne.

 

Zasady logiki to jednak nie tylko prawa de Morgana. Warto przypomnieć sobie np. tablice tautologii.