				%FIBONACCI, 25-jan-2014
% Employ pragma declaration.
% Use integer vs. int declartion on IO for fib/3, else negative numbers produced.

% https://bugs.mercurylang.org/view.php?id=312

%fibonacciSa 487>uname -a
%Darwin luke-immess-imac-2.local 13.0.0 Darwin Kernel Version 13.0.0: Thu Sep 19 22:22:27 PDT 2013; root:xnu-2422.1.72~6/RELEASE_X86_64 x86_64

%fibonacciSa 485>gcc --version
%i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646)
%Copyright (C) 2007 Free Software Foundation, Inc.
%This is free software; see the source for copying conditions.  There is NO
%warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
%
%fibonacciSa 483>

%fibonacciSa 483>mmc -version
%mercury_compile: invalid grade `ion'
%Mercury Compiler, version 13.05, configured for x86_64-apple-darwin12.5.0
%Copyright (C) 1993-2013 The University of Melbourne
%Usage: mmc [<options>] <arguments>
%Use `mmc --help' for more information.
%fibonacciSa 484>

%BUILD
% fibonacciSa 500>./fibonacciSa.bash
% i.e,
% mmc --make --fully-strict -E -v -O 0 --use-subdirs fibonacciSa

% Lets try:
%fibonacciSa 483>mmc  --grade none.gc.stseg --fully-strict -E -v -O 0 --use-subdirs fibonacciSa
% Same problem, fails at 93.


% In:    1 2 3 4 5 6 7 8 9
% Out: 1 1 2 3 5 8 13 21

% RUN
% fibonacciSa 487>./fibonacciSa
% Fibonacci
% Input 1, 2, 3, 4, 5, 6..., output: 1, 1, 2, 3, 5, 8,...
% 1
% fib(1)=1.

% 2
% fib(2)=1.

% 3
% fib(3)=2.

% 4
% fib(4)=3.

% 5
% fib(5)=5.

% 6
% fib(6)=8.

% 7
% fib(7)=13.

% 8
% fib(8)=21.

% 93
% fib(93)=12200160415121876738.

% 500
% fib(500)=139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125.

% 501
% fib(501)=225591516161936330872512695036072072046011324913758190588638866418474627738686883405015987052796968498626.

% 502
% fib(502)=365014740723634211012237077906479355996081581501455497852747829366800199361550174096573645929019489792751.

% 600
% fib(600)=110433070572952242346432246767718285942590237357555606380008891875277701705731473925618404421867819924194229142447517901959200.

% 4000
% fib(4000)=39909473435004422792081248094960912600792570982820257852628876326523051818641373433549136769424132442293969306537520118273879628025443235370362250955435654171592897966790864814458223141914272590897468472180370639695334449662650312874735560926298246249404168309064214351044459077749425236777660809226095151852052781352975449482565838369809183771787439660825140502824343131911711296392457138867486593923544177893735428602238212249156564631452507658603400012003685322984838488962351492632577755354452904049241294565662519417235020049873873878602731379207893212335423484873469083054556329894167262818692599815209582517277965059068235543139459375028276851221435815957374273143824422909416395375178739268544368126894240979135322176080374780998010657710775625856041594078495411724236560242597759185543824798332467919613598667003025993715274875.

% e
% Input is not a number.
% хорошо́ EOF, Quit
% fibonacci 487>

:- module fibonacci. % name of file, for now
:- interface.
:- import_module io.

:- pred main(io, io).
:- mode main(di, uo) is det.

:- implementation.
:- import_module integer, list, string.

:- pred main1(io, io).
:- mode main1(di, uo) is det.


				% Too slow at 40, if pragma not used.
				% Note: use integer not int as a data type, else numeric overflow produces negative result.
% In:    1 2 3 4 5 6 7 8 9
% Out: 1 1 2 3 5 8 13 21
:- func fib(integer, integer, integer) = integer. % integer is very large, i.e., do not use int data type.
:- mode fib(in, in, in) = out is det.
:- pragma memo(fib/3).		% cache fib(x) return values!
fib(N, One, Two) = X :-
	(if N = One then
		X = One
	else if N = Two then
	        X = One
	else
		X = fib(N-One, One, Two) + fib(N-Two, One, Two)
	).

:- func fibStr(integer) = string.
:- mode fibStr(in) = out is det.
fibStr(N) = Sfib :-
	Two = integer.integer(2),
	One = integer.integer(1),
	Fib = fib(N, One, Two),
	Sfib = integer.to_string(Fib).

main(In, Out) :-
	write_string("Fibonacci\nInput 1, 2, 3, 4, 5, 6,..., output: 1, 1, 2, 3, 5, 8,...\n", In, Out1),
	main1(Out1, Out).
	
main1(In, Out) :-
     read_line_as_string(Result, In, Out0), % blank line, wait for input from console
     (
	 Result = eof,		% c^d
	format("хорошо́ EOF, Quit\n", [], Out0, Out)
	;  

	 Result = error(Error),
	 format("IO error: %s\n", [s(io.error_message(Error))], Out0, Out) % IO error from readLine
	; 
	
	Result = ok(FibStr),
	(if string.to_int(string.strip(FibStr), Nok)
	then
	    N = integer.integer(Nok), 
	    format("fib(%d)=%s.\n\n", [i(Nok), s(fibStr(N)) ], Out0, Out1)
	
	 else
	format("Input is not a number.\n", [], Out0, Out1)  % e.g.: letter, a
	),
	main1(Out1, Out)  % tail recursive
     ).