3

I'm trying to specify a DCG for a valid number that would be used like so:

value(Number) --> valid_number(Number).

Basically checking if a specified value is numeric, (it could also be a variable, so it's necessary to check).

I don't know how to build this valid_number DCG/predicate though.

Right now I just have:

valid_number('1') --> ['1'].
valid_number('2') --> ['2'].
...

Which works but it obviously terrible. Trying something like:

valid_number(Number) --> { integer(Number), Number = Number }.

Which both doesn't work and admittedly looks pretty gross as well (I'm sorry, very new to Prolog and trying to learn best practices).

How would I go about building this DCG/predicate that validates whether or not it's a number?

false
  • 10,264
  • 13
  • 101
  • 209
Doug Smith
  • 29,668
  • 57
  • 204
  • 388
  • 2
    The goal `Number = Number` *always* holds. You can remove it. – mat Sep 30 '15 at 16:47
  • Take a look at [this](http://www.swi-prolog.org/pldoc/doc/swi/library/dcg/basics.pl?show=src#number/3) for inspiration. –  Sep 30 '15 at 20:08

2 Answers2

5

I give you a code sample that describes natural numbers:

:- set_prolog_flag(double_quotes, chars).

natural_number(N) --> number_(Cs), { number_codes(N, Cs) }.

number_([D|Ds]) --> digit(D), number_(Ds).
number_([D])    --> digit(D).

digit(D) --> [D], { char_type(D, digit) }.

Example usage:

?- phrase(natural_number(N), "123").
N = 123 ;
false.

I leave generalizing this to other numbers as an exercise.

mat
  • 40,498
  • 3
  • 51
  • 78
  • 2
    Wouldn't it be nice to write this in such a manner that it runs with `double_quoted` set to `chars`, too? – false Sep 30 '15 at 16:48
  • 1
    As `code_type/2` is not a standard predicate, not even a common one, you can use instead `digit(D) --> [D], {D >= 0'0, D =< 0'9}.` for a more portable solution. – Paulo Moura Sep 30 '15 at 17:16
3

Here's an ABNF grammar for a numeric literal such as you might find in a computer language:

NUMERIC-CONSTANT = INTEGER-PART 0*1(FRACTIONAL-PART) 0*1(EXPONENT)

INTEGER-PART = 0*1(SIGN) 1*(DIGIT)

FRACTIONAL-PART = 0*1( DECIMAL-POINT 1*(DIGIT) )

EXPONENT = EXP 0*1(SIGN) 1*(DIGIT)

EXP = "E" / "e"

DECIMAL-POINT = "."

SIGN = "+" / "-"

DIGIT = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"

Since there's no left recursion in this grammar, this lends itself directly to a recursive descent parser, such as produced by a Prolog DCG:

numeric_constant --> integer , optional_fraction , optional_exponent .

integer --> optional_sign , digits .

optional_sign --> sign .
optional_sign --> [].

digits --> digit , digits .

optional_fraction --> fraction .
optional_fraction --> [].

fraction --> decimal_point , digits .

optional_exponent --> exponent .
optional_exponent --> [].

exponent --> exp , optional_sign , digits .

exp --> ['E'] .
exp --> ['e'] .

decimal_point --> ['.'] .

sign --> ['+'] .
sign --> ['-'] .

digit --> ['0'] .
digit --> ['1'] .
digit --> ['2'] .
digit --> ['3'] .
digit --> ['4'] .
digit --> ['5'] .
digit --> ['6'] .
digit --> ['7'] .
digit --> ['8'] .
digit --> ['9'] .
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135