6

I'm experimenting with Coq's extraction mechanism to Haskell. I wrote a naive predicate for prime numbers in Coq, here it is:

(***********)
(* IMPORTS *)
(***********)
Require Import Coq.Arith.PeanoNat.

(************)
(* helper'' *)
(************)
Fixpoint helper' (p m n : nat) : bool :=
  match m,n with
  | 0,_ => false
  | 1,_ => false
  | _,0 => false
  | _,1 => false
  | S m',S n' => (orb ((mult m n) =? p) (helper' p m' n))
  end.

(**********)
(* helper *)
(**********)
Fixpoint helper (p m : nat) : bool :=
  match m with
  | 0 => false
  | S m' => (orb ((mult m m) =? p) (orb (helper' p m' m) (helper p m')))
  end.

(***********)
(* isPrime *)
(***********)
Fixpoint isPrime (p : nat) : bool :=
  match p with
  | 0 => false
  | 1 => false
  | S p' => (negb (helper p p'))
  end.

Compute (isPrime 220).

(*****************)
(* isPrimeHelper *)
(*****************)
Extraction Language Haskell.

(*****************)
(* isPrimeHelper *)
(*****************)
Extraction "/home/oren/GIT/CoqIt/Primes.hs" isPrime helper helper'.

And after extracting the Haskell code, I wrote a simple driver to test it. I ran into two issues:

  1. Coq exported its own Bool instead of using Haskell's built in boolean type.
  2. Coq also used its own nat, so I can't ask isPrime 6 and I have to use S (S (...)).
module Main( main ) where    
import Primes    
main = do
    if ((isPrime (
        Primes.S (
        Primes.S (
        Primes.S (
        Primes.S (
        Primes.S (
        Primes.S ( O ))))))))
        ==
        Primes.True)
    then
        print "Prime"
    else
        print "Non Prime"
HTNW
  • 27,182
  • 1
  • 32
  • 60
OrenIshShalom
  • 5,974
  • 9
  • 37
  • 87

2 Answers2

8

Regarding your first point - try to add

Require Import ExtrHaskellBasic.

to your Coq source. It specifies that the extraction should use Haskell's prelude definitions for some basic types. Documentation can be found here. There is also a similar module for strings.

mschmidt
  • 2,740
  • 4
  • 17
  • 31
2

I'm posting a complete solution here to make this post self contained. Hope others can make use of it.

(***********)
(* IMPORTS *)
(***********)
Require Import Coq.Arith.PeanoNat.

(************)
(* helper'' *)
(************)
Fixpoint helper' (p m n : nat) : bool :=
  match m,n with
  | 0,_ => false
  | 1,_ => false
  | _,0 => false
  | _,1 => false
  | S m',S n' => (orb ((mult m n) =? p) (helper' p m' n))
  end.

(**********)
(* helper *)
(**********)
Fixpoint helper (p m : nat) : bool :=
  match m with
  | 0 => false
  | S m' => (orb ((mult m m) =? p) (orb (helper' p m' m) (helper p m')))
  end.

(***********)
(* isPrime *)
(***********)
Fixpoint isPrime (p : nat) : bool :=
  match p with
  | 0 => false
  | 1 => false
  | S p' => (negb (helper p p'))
  end.

Compute (isPrime 220).

(********************************)
(* Extraction Language: Haskell *)
(********************************)
Extraction Language Haskell.

(***************************)
(* Use Haskell basic types *)
(***************************)
Require Import ExtrHaskellBasic.

(****************************************)
(* Use Haskell support for Nat handling *)
(****************************************)
Require Import ExtrHaskellNatNum.
Extract Inductive Datatypes.nat => "Prelude.Integer" ["0" "succ"]
"(\fO fS n -> if n Prelude.== 0 then fO () else fS (n Prelude.- 1))".

(***************************)
(* Extract to Haskell file *)
(***************************)
Extraction "/home/oren/GIT/CoqIt/Primes.hs" isPrime helper helper'.  

And here is the driver:

module Main( main ) where

import Primes
import Prelude

main = do
    if ((isPrime 220) == True)
    then
        print "Prime"
    else
        print "Non Prime"

It's interesting to mention the huge time difference between Coq's slow Compute (isPrime 220) and Haskell's compiled (and optimized!) super fast version of (is Prime 220).

OrenIshShalom
  • 5,974
  • 9
  • 37
  • 87
  • 1
    I don't think the time difference in your last comment is worth mentioning. Working with type `nat` in Coq is only interesting for proof purposes, not for computation purposes. – Yves Mar 19 '19 at 14:16
  • I get `illegal begin of vernac` error when I try to compile it – radrow Mar 20 '19 at 08:38
  • @Yves I've posted a question on estimating running times of extracted code here: https://stackoverflow.com/questions/55796487/predict-running-times-of-extracted-coq-code-to-haskell ... I wondered if you could answer it? I think it's interesting to be able to predict running times somehow from Coq code itself no? – OrenIshShalom Apr 22 '19 at 15:03
  • @radrow As explained in the beginning of https://coq.github.io/doc/v8.14/refman/addendum/extraction.html, in recent versions of Coq, you apparently need the line `From Coq Require Extraction.` before any extraction commands will work. If you don't have that line, then you get the `illegal begin of vernac` error when you try to use `Extraction`. This is at least the case since Coq 8.8, but may also be true in previous versions as well. – illabout Dec 11 '21 at 11:58