Sunday, September 23, 2012

논리 표현(Logical Expressions)

프로그램이 실제로 수행하는 작업들은 전부 표현에 의해 이루어 집니다. 프로그램 내부에 존재하는 모든 부분에 있어서 그것이 값을 도출하던지 혹은 부작용을 도출 한다고 하더라도 모두 표현이라고 불립니다. 상당히 정의가 광범위한데, 상수인 42라거나 문자열인 "hello" 같은 경우에도 각각 42와 "hello"라는 값을 생성 해 내기 때문에 표현이라고 불립니다.

참고 : 값을 생성하는것과 변수를 정의하는 것을 혼동하지 맙시다. 값이라고 해서 꼭 변수와 연관 지어지는 것은 아닙니다.

writeln과 같은 함수 또한 부작용을 가지고 있으므로 표현입니다. writeln의 경우, 순작용은 문자들을 배열하여 스트림으로 출력 하는 것입니다. 우리가 이제것 제작했던 프로그램을 또 다른 예로 들자면, 변수 지정 또한 표현이 될 수 있는데, 순기능은 값을 왼쪽 변수에 지정 하는 것입니다.

값을 생성 해 낸다는 측면에서 표현은 다른 표현 안에 포함 될 수도 있습니다. 때문에 간단한 표현에서 부터 복잡한 표현을 만들어 내는 것도 가능합니다. 예를 들면 currentTemperature()라는 함수가 있고, 이 함수는 현재의 공기 온도를 도출한다고 가정합시다. 이 함수가 도출하는 값은 writeln표현에 바로 적용 될 수 있습니다:

    writeln("It's ", currentTemperature(),
            " degrees at the moment.");
위 코드는 4개의 표현으로 이루어 져 있습니다:
  1. "It' s "
  2. currentTemperature()
  3. " degrees at the moment."
  4. 위 세개를 이용하는 writeln 표현
이 챕터에서는 조건문에서 사용하는 특수한 표현을 다룰것입니다.

더 나아가기 전에, 지정 연산자의 좌변과 우변에 촛점을 맞추어 다시 한번 더 언급 하자면: 지정 연산자(=)는 표현의 오른쪽에 있는 값을 왼쪽의 값에 할당합니다.(즉 변수에 할당)
    temperature = 23      // temperature's value becomes 23

논리 표현

논리 표현은 불리언 연산에서 사용되는 표현입니다. 논리 표현은 "만약 답변이 '예' 라면 파일을 저장 하겠다" 와 같이 컴퓨터가 결정을 하도록 하는 표현입니다.

논리 표현은 오로지 2가지 값만을 가집니다:false는 거짓을 나타내는 값이며, true는 참을 나타냅니다. 예를 들면, "지중해는 바다다" 라는 표현은 true가 되며, "지중해는 호수다" 라는 표현은 false가 되겠습니다.

다음 예제에서 writeln을 사용하겠습니다. 만약 줄의 맨 끝에 true가 출력된다면, 출력된 줄은 참이라는 것을 의미 합니다. 비슷하게, false가 출력되면 그 줄은 거짓이라는 의미 입니다. 예를 들면, 프로그램의 출력이 다음과 같다면,
커피가 있다: true
이럴 경우 "커피가 있다" 가 됩니다. 같은 방식으로
커피가 있다: false
이는 "커피가 없다"를 의마하게 됩니다. 왼쪽에 있는 "있다"가 커피가 있다라는 것을 의미하는것이라고 생각 하시면 안됩니다. 이 경우에는 "없다" 혹은 "있다는 것은 거짓이다" 라는 것을 의미 합니다.

논리 표현은 조건문, 루프(loop), 함수 인자 등에서 매우 광범위하게 사용됩니다. 이러한 것들이 어떻게 구동하는지 이해하는 것은 매우 중요합니다. 다행히도, 논리 표현은 설명하기도, 사용하기도 매우 쉽습니다.

논리 표현에서의 논리 연산자는 다음과 같이 표현 됩니다:

  • ==연산자는 "왼쪽과 오른쪽은 같나?"라는 질문에 답을 합니다. 같으면 true를 출력하고 다르면  false를 출력합니다. 정의상, ==가 출력 하는 값 또한 논리 표현 입니다.
예를 들면 다음과 같이 2개의 변수가 있다고 가정 합시다:

        int daysInWeek = 7;
        int monthsInYear = 12;
    
    다음의 표현은 위의 두 변수를 사용하는 논리표현입니다:
        daysInWeek == 7           // true
        monthsInYear == 11        // false
  • != 연산자는 "같지 않은가?" 라는 질의에 따라 양변의 표현을 비교하여 == 연산자와는 반대되는 출력을 합니다.
    daysInWeek != 7           // false
    monthsInYear != 11        // true


  • ||연산자는 양 변의 논리 표현이 어느 한쪽이라도 옳다면 true를 출력합니다.

  • 만약 왼쪽의 표현이 true라면, 오른쪽의 표현은 아예 확인하지도 않고 true를 출력합니다. 만약 왼쪽 값이 false라면 오른쪽 표현의 결과를 출력하게 됩니다. 오른쪽이 참이면 true, 거짓이면 false를 출력합니다. ||연산자는 영어에서의 "or" 한국어에서의 "혹은"을 의미 합니다:왼쪽 혹은 오른쪽 혹은 양쪽 다 참일 경우 true를 출력합니다.

    ||논산자를 사용하여 표현 할 수 있는 경우들과 결과들을 다음 표에서 정리하였습니다.
    Left expressionRight expressionResult
    거짓거짓false
    거짓true
    거짓 (연산 안함)true
    참 (연산 안함)true
    import std.stdio;
    
    void main()
    {
        // false means "no", true means "yes"
    
        bool existsCoffee = false;
        bool existsTea = true;
    
        writeln("There is warm drink: ",
                existsCoffee || existsTea);
    }
    
    existsCoffee나 existsTea중 둘중 하나는 적어도 true이기 때문에, 위 의 논리 표현은 참입니다.

    • &&연산자는 영어로는 "and", 한국어로는 "그리고"를 나타내며, 양 변의 논리 표현이 모두 참일 경우에만 true를 출력합니다.

    만약 왼쪽의 논리 표현이 false라면, 오른쪽 표현은 연산 하지 않고 바로 false를 출력합니다. 만약 왼쪽 표현이 true이라면 오른쪽 표현의 결과를 출력합니다.(참일 경우 true, 거짓일 경우 false)
    이 연산자는 영어의 "and"와 비슷하며 한국어의 "그리고"와 비슷합니다:왼쪽, 그리고 오른쪽의 값이 모두 참일경우, true를 출력합니다.
    왼쪽표현오른쪽표현결과
    falsefalse (not evaluated)false
    falsetrue (not evaluated)false
    truefalsefalse
    truetruetrue
        writeln("I will drink coffee: ",
                wantToDrinkCoffee && existsCoffee);
    
    참고:||연산자와 &&연산자는 위에서 설명 하였듯이 경우에 따라서는 오른쪽 표현을 연산하지 않습니다. 이러한 것을 shortcut(생략)이라고 합니다.(역자 주: 사실 "shortcut"이라는 단어를 어떻게 번역해야 할지 모르겠습니다만 의미는 충분히 전달되리라 생각합니다.) 이와 같이 경우에 따라서 생략을 하는 연산자는 삼항연산자 ?:를 제외하고는 이제 없으며, 후에 다른 챕터에서 다룰 예정입니다. 다른 연산자는 항상 모든 표현을 연산합니다.
    (역자 주 : 물론 직접 만든 연산자나 연산자 오버로딩(operation overloading)으로 만든 경우에는 사용자의 마음에 달렸겠죠.)

    • ^연산자는 "이것 혹은 저것?"을 나타냅니다. 이 연산자는 하나의 표현만 참일 경우 true를 출력하며, 둘 다 참일 경우 false를 출력합니다.

    왼쪽표현오른쪽 표현결과
    falsefalsefalse
    falsetruetrue
    truefalsetrue
    truetruefalse
    예를 들어, 제가 체스를 두는데, 친구 한명만 나타나야지 별탈없이 체스를 두겠죠:
        writeln("I will play chess: ", jimShowedUp ^ bobShowedUp);
    
    
    • <연산자는 "오른쪽보다 작은가?"(혹은 "순서상에서 먼저 나오는가?")를 나타냅니다.
        writeln("We beat: ", theirScore < ourScore);
    

    • >연산자는 "오른쪽보다 큰가?"(혹은 "순서상으로 나중에 나오는가?")를 나타냅니다.
        writeln("They beat: ", theirScore > ourScore);
    

    • <=연산자는 "오른쪽보다 작거나 같은가?"(혹은 "오른쪽과 순서가 같거나 먼저 나오는가?")를 나타냅니다. >연산자와 정 반대입니다.

        writeln("We were not beaten: ", theirScore <= ourScore);
    

    • >=연산자는 "오른쪽보다 크거나 같은가?"(혹은 "오른쪽과 순서가 같거나 나중에 나오는가?")를 나타냅니다. <연산자의 정 반대입니다.

        writeln("We did not beat: ", theirScore >= ourScore);
    

    • !연산자는 "오른쪽의 반대의"라는 의미입니다. 다른 논리연산자들과는 다르게, 오직 하나의 표현만을 받으며, 만약 그 표현이 false라면 true를, false라면 true를 출력합니다.

        writeln("I will walk: ", !existsBicycle);
    

    그룹 표현(Grouping expressions)

    표현들을 연산하는 순서는 괄호로 묶어서 정리 할 수 있습니다. 여러 표현들 중에서 괄호로 묶여 있는 표현이 존재 한다면, 괄호로 묶여 있는 표현들을 먼저 연산합니다. 예를 들면, 만약 커피나 차가 있다면, 그리고 쿠키랑 빵이 있다면;그럼 행복하겠네" 라는 문장은 다음과 같이 코드로 변환 할 수 있습니다:
    writeln("I am happy: ",
    (existsCoffee || existsTea) && (existsCookie || existsScone));
    
    만약 하위 표현들이 괄호로 묶여 있지 않다면, D가 정해 놓은 연산자 순서에 따라 연산을 합니다(C 언어에서 차용한 것들입니다). 이런 법칙에 따르면 && 연산자는 ||보다 우선순위를 가집니다. 그러므로 괄호가 없이 표현을 정리하자면 다음과 같이 코드가 짜여 지겠습니다:
    writeln("I am happy: ",
    existsCoffee || existsTea && existsCookie || existsScone);
    
    &&연산자의 표현이 먼저 연산되며, 위의 표현은 의미상으로 다음과 같은 표현이 됩니다:
    writeln("I am happy: ",
    existsCoffee || (existsTea && existsCookie) || existsScone);
    
    완전 다른 의미가 됩니다: "커피가 있다면, 혹은 차 그리고 쿠키가 있다면, 혹은 빵이 있다면;나는 행복하겠네".

    논리 입력 읽기

    위에서 사용한 모든 논리값들은 자동적으로 "false" 혹은 "true"로 출력됩니다. 하지만 그 반대는 되지 않습니다: 문자열 "false" 혹은 "true"는 자동적으로 bool 타입의 "false"나 "true"로 변경되지 않습니다. 그렇기 때문에, 입력을 먼저 문자열로 입력 받은 뒤에 bool 타입으로 변경되어야 합니다.

    아래의 연습문제들중 하나는 "false" 혹은 "true"를 표준입력으로 받아야 하는 프로그램을 만들어야 하는데, 아직 설명하지 않은 내용을 사용하였습니다. 입력을 bool 값으로 변경하는 함수를 제작하였습니다. std.convto를 호출하였습니다.(만약 잘못된 값을 넣으면 ConvException 에러가 출력됩니다.)

    적어도 main 함수에 있는 내용들은 이해하였으면 좋겠습니다. read_bool() 은 아직 배우지 않는 내용을 다루고 있기에, 설명을 첨부 하였지만 지금은 무시 하셔도 좋습니다. 그래도 컴파일하려면 필요한 부분이기에 코드에 첨부 하셔야 합니다.

    연습문제

    1. 위에서 설명 하였듯이, <> 는 하나의 값이 다른 값보다 큰지 작은지 결정하는 연산자 입니다; 하지만 "중간값인가?" 라는, 어떤 값이 다른 두 값 사이에 있는지 결정하는 연산자는 없습니다.

      value라는 값이 10과 20 사이에 있는지 결정하는 프로그램을 만들었다고 가정 합시다. 하지만 아래의 코드는 컴파일이 되지 않습니다:
      import std.stdio;
      
      void main()
      {
          int value = 15;
      
          writeln("Is between: ",
                  10 < value < 20);        // ← compilation ERROR
      }
      
      괄호를 넣어 봤지만:
          writeln("Is between: ",
                  (10 < value < 20));      // ← compilation ERROR
      
      그래도 컴파일 되지 않습니다.

      해결법을 찾던 도중, 다음과 같은 괄호 사용법이 컴파일이 되도록 하다는 것을 알아 냈습니다:
          writeln("Is between: ",
                  (10 < value) < 20);      // ← compiles but WRONG
      
      이제 프로그램은 의도 했던대로 "true"를 출력합니다. 하지만 안타깝게도 답은 틀렸습니다. 프로그램에 버그가 있군요. 이 버그를 확인 하기 위해 15를 20보다 큰 값으로 바꿔서 컴파일 해봅시다:
          int value = 21;
      
      21은 20보다 크지만 "true"를 출력 하는군요.
      힌트: 논리 표현의 타입은 bool 입니다. bool 값이 20보다 작은지 큰지 결정하는것은 의미가 없습니다.

      논리 표현에서 "중간값인가" 라는 표현은 "하한값보다 큰가?. 그리고 상한값보다 작은가?" 라고 바꿔야 합니다.

      표현을 위의 논리에 따라 변경하고 컴파일을 해서 "true"를 나타내는지 확인 해 봅시다. 추가로, 다른 값을 넣었을때도 잘 작동하는지 확인 해 봅시다: 예를 들면 value를 50이나 1로 바꾸어 봅시다. 그렇다면 "false"가 출력 되어야 하겠죠. 12를 넣는다면 "true"'를 출력해야 합니다.

    1. 다음과 같은 조건을 만족한다면 해변에 간다고 가정합시다:
      • 거리가 10 이하면 모두 자전거를 타고 해변에 갑니다.
      • 인원이 6명 미만이고, 차가 있고, 운전면허가 있다면 해변에 갑니다.

        아래 프로그램은 항상 "true"를 출력합니다. 위의 조건들이 만족하는 경우에만 "true"를 표현하도록 고쳐 봅시다.(프로그램을 실행했을때, "false"혹은 "true"를 받는 질문은 항상 "입니까?"로 끝나야 합니다.). read_bool()를 포함해야 한다는것을 잊지 맙시다:
      import std.stdio;
      import std.conv;
      import std.string;
      
      void main()
      {
          write("How many are we? ");
          int personCount;
          readf(" %s", &personCount);
      
          write("How many bicycles are there? ");
          int bicycleCount;
          readf(" %s", &bicycleCount);
      
          write("What is the distance to the beach? ");
          int distance;
          readf(" %s", &distance);
      
          bool existsCar = read_bool("Is there a car? ");
          bool existsLicense =
              read_bool("Is there a driver license? ");
      
          /*
            Replace the 'true' below with a logical expression that
            produces the value 'true' when one of the conditions
            listed in the question is satisfied:
           */
          writeln("We are going to the beach: ", true);
      }
      
      /*
        Please note that this function includes features that will
        be explained in later chapters.
       */
      bool read_bool(string message)
      {
          // Print the message
          write(message, "(false or true) ");
      
          // Read the line as a string
          string input;
          while (input.length == 0) {
              input = chomp(readln());
          }
      
          // Produce a 'bool' value from that string
          bool result = to!bool(input);
      
          // Return the result to the caller
          return result;
      }
      
      여러가지 값들을 넣어보고 의도했던대로 동작하는지 확인 해 봅시다.

    No comments:

    Post a Comment