このディレクトリの索引
#  出典 :: C/C++の宿題片付けます 153代目 #137
#  [1] 授業単元:基礎プロ 
#  [2] 問題文(含コード&リンク): 
#  キーボードから自然数 n を読み込む. 
#  読み込んだ自然数 n の階乗を計算する. 
#  計算結果を以下の実行例のように出力する. 
#   
#  実行例 
#  >./extra06-1 
#  自然数を入力: 5 
#  5! = 1 x 2 x 3 x 4 x 5 = 120 
#  >./extra06-1 
#  自然数を入力: 6 
#  6! = 1 x 2 x 3 x 4 x 5 x 6 = 720 
#  > 
#   
#  この動作をするプログラムを作成せよ 
#  

'キーボードから自然数 n を読み込む.読み込んだ自然数 n の階乗を計算する.計算結果を以下の実行例のように出力する.' :-
'キーボードから自然数 n を読み込む'(_n),
'読み込んだ自然数 n の階乗を計算する.'(_n,_階乗式の文字列表現,_nの階乗),
'計算結果を以下の実行例のように出力する.'(_n,_階乗式の文字列表現,_nの階乗).

'キーボードから自然数 n を読み込む'(_n) :-
自然数を読み込む(_n).

'読み込んだ自然数 n の階乗を計算する.'(_n,_1からnまでの数ならび,_nの階乗) :-
findall(N,between(1,_n,N),_1からnまでの数ならび),
mult_list(_1からnまでの数ならび,_nの階乗).

mult_list([],1).
mult_list([A|R],X) :-
mult_list(R,Y),
X is A * Y.

'計算結果を以下の実行例のように出力する.'(_n,_1からnまでの数ならび,_nの階乗) :-
atomic_list_concat(_1からnまでの数ならび,' × ',_階乗式の表示用文字列),
writef('%w! = %w = %w\n',[_n,_階乗式の表示用文字列,_nの階乗]).

自然数を読み込む(_自然数) :-
催促を出力した後に行入力(_行),
自然数を読み込み診断(_行,_自然数),!.
自然数を読み込む(_自然数) :-
自然数を読み込む(_自然数).

催促を出力した後に行入力(_行) :-
write('自然数を入力 : '),
行入力(_行).

自然数を読み込み診断(_行,_自然数) :-
catch(read_term_from_atom(_行,_自然数,[]),E,fail),
自然数(_自然数),!.
自然数を読み込み診断(_行,_) :-
writef('入力された %w からは自然数が得られません。再入力をお願いします。\n',[_行]),
fail.

自然数(_自然数) :-
integer(_自然数),
_自然数 >= 0,!.

行入力(_行) :-
read_line_to_codes(current_input,Codes),
atom_codes(_行,Codes).

%  
%  何故findmult/3を使わなかったか?
%
%  目下の課題は以下の実行例をどのように述語定義の中に取り込むかだ
%  コメントはそのまま引数ゼロの述語として定義し、副目標として書いて置けばよいが
%  このような改行のある事例は述語アトムとして見やすいものにならない。
%
/*
#  実行例 
#  >./extra06-1 
#  自然数を入力: 5 
#  5! = 1 x 2 x 3 x 4 x 5 = 120 
#  >./extra06-1 
#  自然数を入力: 6 
#  6! = 1 x 2 x 3 x 4 x 5 x 6 = 720 
#  > 
*/