2021/08/28

TypeScript入門 第3回 関数定義

1)はじめに

前回, 逆ポーランド記法で記述した数式を計算するプログラムを作成しました. しかし, 計算する数式をソースコードに埋め込んであって, 数式を変更するためにはソースコードを編集してコンパイルしなくてはなりません. 使い物にならないので, プログラムとしての体裁を整えていきます.

2)関数の定義

計算する部分を関数として定義し, 計算する数式を引数として与えられるようにします. 関数の戻り値は, 計算した結果とします. 計算の過程を記録するスタックは, 関数の中で定義するローカル変数とします. ソースコードは次のようになりました.

// 配列を逆ポーランド記法で記述した式として計算する.
function calc(inputstring[]) {
    let stacknumber[] = []
    for (let value of input) {
        if (value === '+') {
            let a = stack.pop()
            let b = stack.pop()
            if ('number' === typeof a && 'number' === typeof b) {
                stack.push(a + b)
            } else {
                throw new Error('数字が入ってないよ')
            }
        } else if (value === '*') {
            let a = stack.pop()
            let b = stack.pop()
            if ('number' === typeof a && 'number' === typeof b) {
                stack.push(a * b)
            } else {
                throw new Error('数字が入ってないよ')
            }
        } else {
            let a = parseInt(value)
            stack.push(a)
        }
    }

    if (1 === stack.length) {
        return stack.pop()
    } else {
        throw new Error('スタックの要素数が1ではありません. 式を間違えているかも?')
    }
}

// 計算してみる
console.log(calc(['2''3''+''4''*']))

関数名は「calc」としました. 注意点は次の通りです.

  1. 引数名に続けて引数の型を指定する必要があります. 関数の戻り値の型も指定できますが, コンパイラに型推論させる方が良いようです.
  2. 計算結果をコンソールへ出力するコードは削除しました.
  3. 入力をすべて処理できれば, 計算結果を返します. この時, スタックの要素数が1であることを確認し, 1でない時はエラーを投げています.
  4. 関数定義に続いて, 動作確認用のコードを入れています.

このソースコードをコンパイルし実行すると, 計算結果として「20」を表示しました. 問題なく動作しています.

3)演算子の種類を増やす

今のソースコードでは, 対応している演算子は「+」と「×」の2種類だけです. 少なくとも「-」と「/」は対応しておきたいところです. 「+」や「×」を計算するコードをコピーして編集すれば簡単に対応できますが, 似たようなコードが繰り返し現れるのは気持ちの良いものではありません. そこで, 補助関数を導入して全体を見やすくします. 合わせて, 「-」と「/」にも対応します. ソースコードは次のようになりました.

// 補助関数
function calcAux(stacknumber[], op: (anumberbnumber=> number) {
    let b = stack.pop()
    let a = stack.pop()
    if ('number' === typeof a && 'number' === typeof b) {
        stack.push(op(ab))
    } else {
        throw new Error('数字が入ってないよ')
    }
}

// 配列を逆ポーランド記法で記述した式として計算する.
function calc(inputstring[]) {
    let stacknumber[] = []
    for (let value of input) {
        if (value === '+') {
            calcAux(stack, (ab=> a + b)
        } else if (value === '-') {
            calcAux(stack, (ab=> a - b)
        } else if (value === '*') {
            calcAux(stack, (ab=> a * b)
        } else if (value === '/') {
            calcAux(stack, (ab=> a / b)
        } else {
            let a = parseInt(value)
            stack.push(a)
        }
    }

    if (1 === stack.length) {
        return stack.pop()
        
    } else {
        throw new Error('スタックの要素数が1ではありません. 式を間違えているかも?')
    }
}

// 計算してみる
console.log(calc(['2''3''+''4''*''5''/''2''-']))

補助関数の引数は, スタックと演算子に対応した関数を取れるようにしています. このようなプログラミング技法に慣れていない方は, 関数型プログラミングに関する書籍などで勉強することをお勧めします. 

補助関数の注意点として, スタックからポップした値を変数に割り当てる順序を「a, b」から「b, a」に変更しています. 引き算や割り算では, この順序を間違えると正しい答えは得られません. 補助関数を使うことで, calc関数の見通しが良くなりました. このソースコードをコンパイルし実行すると, 計算結果として「2」を表示しました. 問題なく動作しています.

3)まとめ

この記事では, 前回, 作成したプログラムの構成を変更し関数を定義して, プログラムらしく仕上げました. また, 計算のための補助関数は, 関数そのものを引数として与えられるように定義しました. TypeScriptのように型を厳密にチェックしてくれるプログラミング言語であれば, このようなテクニックを安心して使えます. 

しかし, 計算する式を変更するためにソースコードを編集するのは煩わしくなってきました. 次回の記事では, ソースコードを編集せずに計算する式を変更する方法を試します.

最後に, この記事で使用したNode.jsとTypeScriptのバージョンは次の通りです.

PS C:\TSWork\RPN> node --version
v14.17.5
PS C:\TSWork\RPN> .\node_modules\.bin\tsc --version
Version 4.3.5
PS C:\TSWork\RPN>

0 件のコメント:

コメントを投稿

ヒューマン・リソース・マシーン 入社41年目−並べ替えよ

目次 1)課題 0を終端とした文字列がいくつか流れてきます。各文字列に対してソート(並べ替え)を行い、小さい順(昇順)に右側へ運んでください。 2)状況の確認 この問題では, 予めコードが入っています. このコードを実行して, 何をするコードなのか確かめます.  左のコンベアから...