diff --git a/ats-src/combinatorics.dats b/ats-src/combinatorics.dats
--- a/ats-src/combinatorics.dats
+++ b/ats-src/combinatorics.dats
@@ -6,7 +6,6 @@
 staload "contrib/atscntrb-hx-intinf/SATS/intinf_vt.sats"
 staload UN = "prelude/SATS/unsafe.sats"
 
-// TODO fancy/insane bit-flipping?
 fnx fact {n : nat} .<n>. (k : int(n)) : [ n : nat | n > 0 ] intinf(n) =
   case+ k of
     | 0 => int2intinf(1)
diff --git a/cbits/combinatorics.c b/cbits/combinatorics.c
--- a/cbits/combinatorics.c
+++ b/cbits/combinatorics.c
@@ -1,7 +1,7 @@
 /*
 **
 ** The C code is generated by [ATS/Postiats-0-3-8]
-** The starting compilation time is: 2018-1-6:  1h:14m
+** The starting compilation time is: 2018-1-6: 19h:39m
 **
 */
 
@@ -550,7 +550,7 @@
 #endif // end of [QUALIFIED]
 
 /*
-/home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 255(line=10, offs=5) -- 444(line=14, offs=59)
+/home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 220(line=9, offs=5) -- 409(line=13, offs=59)
 */
 /*
 local: fact_0$0(level=0)
@@ -574,11 +574,11 @@
 */
 ATSfunbody_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 255(line=10, offs=5) -- 444(line=14, offs=59)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 220(line=9, offs=5) -- 409(line=13, offs=59)
 */
 ATSINSflab(__patsflab_fact_0):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 325(line=11, offs=3) -- 444(line=14, offs=59)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 290(line=10, offs=3) -- 409(line=13, offs=59)
 */
 ATScaseof_beg()
 /*
@@ -586,15 +586,15 @@
 */
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 342(line=12, offs=7) -- 343(line=12, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 307(line=11, offs=7) -- 308(line=11, offs=8)
 */
 ATSINSlab(__atstmplab0):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 277(line=10, offs=27) -- 278(line=10, offs=28)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 242(line=9, offs=27) -- 243(line=9, offs=28)
 */
 ATSifnthen(ATSCKpat_int(arg0, ATSPMVint(0))) { ATSINSgoto(__atstmplab2) ; } ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 343(line=12, offs=8) -- 343(line=12, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 308(line=11, offs=8) -- 308(line=11, offs=8)
 */
 ATSINSlab(__atstmplab1):
 /*
@@ -604,7 +604,7 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 347(line=12, offs=12) -- 360(line=12, offs=25)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 312(line=11, offs=12) -- 325(line=11, offs=25)
 */
 ATSINSmove(tmpret0, ATSCNTRB_056_HX_056_intinf_vt__intinf_make_int__1__1(ATSPMVi0nt(1))) ;
 
@@ -612,15 +612,15 @@
 
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 367(line=13, offs=7) -- 368(line=13, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 332(line=12, offs=7) -- 333(line=12, offs=8)
 */
 ATSINSlab(__atstmplab2):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 277(line=10, offs=27) -- 278(line=10, offs=28)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 242(line=9, offs=27) -- 243(line=9, offs=28)
 */
 ATSifnthen(ATSCKpat_int(arg0, ATSPMVint(1))) { ATSINSgoto(__atstmplab4) ; } ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 368(line=13, offs=8) -- 368(line=13, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 333(line=12, offs=8) -- 333(line=12, offs=8)
 */
 ATSINSlab(__atstmplab3):
 /*
@@ -630,7 +630,7 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 372(line=13, offs=12) -- 385(line=13, offs=25)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 337(line=12, offs=12) -- 350(line=12, offs=25)
 */
 ATSINSmove(tmpret0, ATSCNTRB_056_HX_056_intinf_vt__intinf_make_int__1__2(ATSPMVi0nt(1))) ;
 
@@ -638,7 +638,7 @@
 
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 393(line=14, offs=8) -- 393(line=14, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 358(line=13, offs=8) -- 358(line=13, offs=8)
 */
 ATSINSlab(__atstmplab4):
 /*
@@ -648,22 +648,22 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 433(line=14, offs=48) -- 438(line=14, offs=53)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 398(line=13, offs=48) -- 403(line=13, offs=53)
 */
 ATSINSmove(tmp19, atspre_g1int_sub_int(arg0, ATSPMVi0nt(1))) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 428(line=14, offs=43) -- 439(line=14, offs=54)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 393(line=13, offs=43) -- 404(line=13, offs=54)
 */
 ATSINSmove(tmp18, fact_0(tmp19)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 412(line=14, offs=27) -- 443(line=14, offs=58)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 377(line=13, offs=27) -- 408(line=13, offs=58)
 */
 ATSINSmove(tmp13, ATSCNTRB_056_HX_056_intinf_vt__mul_intinf0_int__7__1(tmp18, arg0)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 398(line=14, offs=13) -- 444(line=14, offs=59)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 363(line=13, offs=13) -- 409(line=13, offs=59)
 */
 ATSINSmove(tmpret0, ATSPMVcastfn(castvwtp0, atstkind_type(atstype_ptrk), tmp13)) ;
 ATSbranch_end()
@@ -1090,7 +1090,7 @@
 } /* end of [ATSCNTRB_056_HX_056_intinf_vt__mul_intinf0_int__7__1] */
 
 /*
-/home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 520(line=17, offs=5) -- 730(line=26, offs=8)
+/home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 485(line=16, offs=5) -- 695(line=25, offs=8)
 */
 /*
 local: dfact_10$0(level=0)
@@ -1113,11 +1113,11 @@
 */
 ATSfunbody_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 520(line=17, offs=5) -- 730(line=26, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 485(line=16, offs=5) -- 695(line=25, offs=8)
 */
 ATSINSflab(__patsflab_dfact_10):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 568(line=18, offs=3) -- 730(line=26, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 533(line=17, offs=3) -- 695(line=25, offs=8)
 */
 ATScaseof_beg()
 /*
@@ -1125,15 +1125,15 @@
 */
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 585(line=19, offs=7) -- 586(line=19, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 550(line=18, offs=7) -- 551(line=18, offs=8)
 */
 ATSINSlab(__atstmplab5):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 543(line=17, offs=28) -- 544(line=17, offs=29)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 508(line=16, offs=28) -- 509(line=16, offs=29)
 */
 ATSifnthen(ATSCKpat_int(arg0, ATSPMVint(0))) { ATSINSgoto(__atstmplab7) ; } ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 586(line=19, offs=8) -- 586(line=19, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 551(line=18, offs=8) -- 551(line=18, offs=8)
 */
 ATSINSlab(__atstmplab6):
 /*
@@ -1143,7 +1143,7 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 590(line=19, offs=12) -- 603(line=19, offs=25)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 555(line=18, offs=12) -- 568(line=18, offs=25)
 */
 ATSINSmove(tmpret20, ATSCNTRB_056_HX_056_intinf_vt__intinf_make_int__1__3(ATSPMVi0nt(1))) ;
 
@@ -1151,15 +1151,15 @@
 
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 610(line=20, offs=7) -- 611(line=20, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 575(line=19, offs=7) -- 576(line=19, offs=8)
 */
 ATSINSlab(__atstmplab7):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 543(line=17, offs=28) -- 544(line=17, offs=29)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 508(line=16, offs=28) -- 509(line=16, offs=29)
 */
 ATSifnthen(ATSCKpat_int(arg0, ATSPMVint(1))) { ATSINSgoto(__atstmplab9) ; } ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 611(line=20, offs=8) -- 611(line=20, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 576(line=19, offs=8) -- 576(line=19, offs=8)
 */
 ATSINSlab(__atstmplab8):
 /*
@@ -1169,7 +1169,7 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 615(line=20, offs=12) -- 628(line=20, offs=25)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 580(line=19, offs=12) -- 593(line=19, offs=25)
 */
 ATSINSmove(tmpret20, ATSCNTRB_056_HX_056_intinf_vt__intinf_make_int__1__4(ATSPMVi0nt(1))) ;
 
@@ -1177,7 +1177,7 @@
 
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 636(line=21, offs=8) -- 636(line=21, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 601(line=20, offs=8) -- 601(line=20, offs=8)
 */
 ATSINSlab(__atstmplab9):
 /*
@@ -1187,18 +1187,18 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 641(line=21, offs=13) -- 730(line=26, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 606(line=20, offs=13) -- 695(line=25, offs=8)
 */
 /*
 letpush(beg)
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 665(line=22, offs=21) -- 670(line=22, offs=26)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 630(line=21, offs=21) -- 635(line=21, offs=26)
 */
 ATSINSmove(tmp30, atspre_g1int_sub_int(arg0, ATSPMVi0nt(2))) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 659(line=22, offs=15) -- 671(line=22, offs=27)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 624(line=21, offs=15) -- 636(line=21, offs=27)
 */
 ATSINSmove(tmp29, dfact_10(tmp30)) ;
 
@@ -1207,12 +1207,12 @@
 */
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 686(line=23, offs=15) -- 707(line=23, offs=36)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 651(line=22, offs=15) -- 672(line=22, offs=36)
 */
 ATSINSmove(tmpret20, ATSCNTRB_056_HX_056_intinf_vt__mul_intinf0_int__7__2(tmp29, arg0)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 641(line=21, offs=13) -- 730(line=26, offs=8)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 606(line=20, offs=13) -- 695(line=25, offs=8)
 */
 /*
 INSletpop()
@@ -1482,7 +1482,7 @@
 } /* end of [ATSCNTRB_056_HX_056_intinf_vt__mul_intinf0_int__7__2] */
 
 /*
-/home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 793(line=29, offs=4) -- 1003(line=37, offs=6)
+/home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 758(line=28, offs=4) -- 968(line=36, offs=6)
 */
 /*
 local: fact_0$0(level=0)
@@ -1504,37 +1504,37 @@
 /* tmpvardeclst(end) */
 ATSfunbody_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 793(line=29, offs=4) -- 1003(line=37, offs=6)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 758(line=28, offs=4) -- 968(line=36, offs=6)
 */
 ATSINSflab(__patsflab_permutations_16):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 874(line=30, offs=3) -- 1003(line=37, offs=6)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 839(line=29, offs=3) -- 968(line=36, offs=6)
 */
 /*
 letpush(beg)
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 890(line=31, offs=13) -- 896(line=31, offs=19)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 855(line=30, offs=13) -- 861(line=30, offs=19)
 */
 ATSINSmove(tmp34, fact_0(arg0)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 915(line=32, offs=18) -- 920(line=32, offs=23)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 880(line=31, offs=18) -- 885(line=31, offs=23)
 */
 ATSINSmove(tmp36, atspre_g1int_sub_int(arg0, arg1)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 910(line=32, offs=13) -- 921(line=32, offs=24)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 875(line=31, offs=13) -- 886(line=31, offs=24)
 */
 ATSINSmove(tmp35, fact_0(tmp36)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 934(line=33, offs=13) -- 959(line=33, offs=38)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 899(line=32, offs=13) -- 924(line=32, offs=38)
 */
 ATSINSmove(tmp37, ATSCNTRB_056_HX_056_intinf_vt__div_intinf0_intinf1__17__1(tmp34, ATSPMVrefarg0(tmp35))) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 972(line=34, offs=13) -- 985(line=34, offs=26)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 937(line=33, offs=13) -- 950(line=33, offs=26)
 */
 ATSINSmove_void(tmp42, ATSCNTRB_056_HX_056_intinf_vt__intinf_free__19__1(tmp35)) ;
 
@@ -1543,11 +1543,11 @@
 */
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 996(line=36, offs=5) -- 997(line=36, offs=6)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 961(line=35, offs=5) -- 962(line=35, offs=6)
 */
 ATSINSmove(tmpret33, tmp37) ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 874(line=30, offs=3) -- 1003(line=37, offs=6)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 839(line=29, offs=3) -- 968(line=36, offs=6)
 */
 /*
 INSletpop()
@@ -1789,7 +1789,7 @@
 } /* end of [ATSCNTRB_056_HX_056_intinf_vt__intinf_free__19__1] */
 
 /*
-/home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1066(line=40, offs=4) -- 1771(line=64, offs=6)
+/home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1031(line=39, offs=4) -- 1736(line=63, offs=6)
 */
 /*
 local: fact_0$0(level=0)
@@ -1810,11 +1810,11 @@
 /* tmpvardeclst(end) */
 ATSfunbody_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1066(line=40, offs=4) -- 1771(line=64, offs=6)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1031(line=39, offs=4) -- 1736(line=63, offs=6)
 */
 ATSINSflab(__patsflab_choose_21):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1141(line=41, offs=3) -- 1771(line=64, offs=6)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1106(line=40, offs=3) -- 1736(line=63, offs=6)
 */
 /*
 letpush(beg)
@@ -1824,7 +1824,7 @@
 */
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1508(line=53, offs=5) -- 1765(line=63, offs=10)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1473(line=52, offs=5) -- 1730(line=62, offs=10)
 */
 ATScaseof_beg()
 /*
@@ -1832,15 +1832,15 @@
 */
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1527(line=54, offs=9) -- 1528(line=54, offs=10)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1492(line=53, offs=9) -- 1493(line=53, offs=10)
 */
 ATSINSlab(__atstmplab15):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1116(line=40, offs=54) -- 1117(line=40, offs=55)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1081(line=39, offs=54) -- 1082(line=39, offs=55)
 */
 ATSifnthen(ATSCKpat_int(arg1, ATSPMVint(0))) { ATSINSgoto(__atstmplab17) ; } ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1528(line=54, offs=10) -- 1528(line=54, offs=10)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1493(line=53, offs=10) -- 1493(line=53, offs=10)
 */
 ATSINSlab(__atstmplab16):
 /*
@@ -1850,7 +1850,7 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1532(line=54, offs=14) -- 1545(line=54, offs=27)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1497(line=53, offs=14) -- 1510(line=53, offs=27)
 */
 ATSINSmove(tmpret47, ATSCNTRB_056_HX_056_intinf_vt__intinf_make_int__1__7(ATSPMVi0nt(1))) ;
 
@@ -1858,15 +1858,15 @@
 
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1554(line=55, offs=9) -- 1555(line=55, offs=10)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1519(line=54, offs=9) -- 1520(line=54, offs=10)
 */
 ATSINSlab(__atstmplab17):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1116(line=40, offs=54) -- 1117(line=40, offs=55)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1081(line=39, offs=54) -- 1082(line=39, offs=55)
 */
 ATSifnthen(ATSCKpat_int(arg1, ATSPMVint(1))) { ATSINSgoto(__atstmplab19) ; } ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1555(line=55, offs=10) -- 1555(line=55, offs=10)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1520(line=54, offs=10) -- 1520(line=54, offs=10)
 */
 ATSINSlab(__atstmplab18):
 /*
@@ -1876,7 +1876,7 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1559(line=55, offs=14) -- 1571(line=55, offs=26)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1524(line=54, offs=14) -- 1536(line=54, offs=26)
 */
 ATSINSmove(tmpret47, ATSCNTRB_056_HX_056_intinf_vt__intinf_make_int__1__8(arg0)) ;
 
@@ -1884,7 +1884,7 @@
 
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1582(line=56, offs=10) -- 1582(line=56, offs=10)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1547(line=55, offs=10) -- 1547(line=55, offs=10)
 */
 ATSINSlab(__atstmplab19):
 /*
@@ -1894,28 +1894,28 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1587(line=56, offs=15) -- 1765(line=63, offs=10)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1552(line=55, offs=15) -- 1730(line=62, offs=10)
 */
 /*
 letpush(beg)
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1607(line=57, offs=17) -- 1623(line=57, offs=33)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1572(line=56, offs=17) -- 1588(line=56, offs=33)
 */
 ATSINSmove(tmp75, numerator_loop_22(arg0, arg1)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1641(line=58, offs=17) -- 1647(line=58, offs=23)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1606(line=57, offs=17) -- 1612(line=57, offs=23)
 */
 ATSINSmove(tmp76, fact_0(arg1)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1665(line=59, offs=17) -- 1690(line=59, offs=42)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1630(line=58, offs=17) -- 1655(line=58, offs=42)
 */
 ATSINSmove(tmp77, ATSCNTRB_056_HX_056_intinf_vt__div_intinf0_intinf1__17__2(tmp75, ATSPMVrefarg0(tmp76))) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1707(line=60, offs=17) -- 1720(line=60, offs=30)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1672(line=59, offs=17) -- 1685(line=59, offs=30)
 */
 ATSINSmove_void(tmp80, ATSCNTRB_056_HX_056_intinf_vt__intinf_free__19__2(tmp76)) ;
 
@@ -1924,11 +1924,11 @@
 */
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1739(line=62, offs=9) -- 1754(line=62, offs=24)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1704(line=61, offs=9) -- 1719(line=61, offs=24)
 */
 ATSINSmove(tmpret47, ATSPMVcastfn(castvwtp0, atstkind_type(atstype_ptrk), tmp77)) ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1587(line=56, offs=15) -- 1765(line=63, offs=10)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1552(line=55, offs=15) -- 1730(line=62, offs=10)
 */
 /*
 INSletpop()
@@ -1941,7 +1941,7 @@
 ATScaseof_end()
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1141(line=41, offs=3) -- 1771(line=64, offs=6)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1106(line=40, offs=3) -- 1736(line=63, offs=6)
 */
 /*
 INSletpop()
@@ -1951,7 +1951,7 @@
 } /* end of [choose_21] */
 
 /*
-/home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1153(line=42, offs=9) -- 1498(line=51, offs=12)
+/home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1118(line=41, offs=9) -- 1463(line=50, offs=12)
 */
 /*
 local: numerator_loop_22$0(level=1)
@@ -1976,11 +1976,11 @@
 /* tmpvardeclst(end) */
 ATSfunbody_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1153(line=42, offs=9) -- 1498(line=51, offs=12)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1118(line=41, offs=9) -- 1463(line=50, offs=12)
 */
 ATSINSflab(__patsflab_numerator_loop_22):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1247(line=43, offs=7) -- 1498(line=51, offs=12)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1212(line=42, offs=7) -- 1463(line=50, offs=12)
 */
 ATScaseof_beg()
 /*
@@ -1988,15 +1988,15 @@
 */
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1268(line=44, offs=11) -- 1269(line=44, offs=12)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1233(line=43, offs=11) -- 1234(line=43, offs=12)
 */
 ATSINSlab(__atstmplab10):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1195(line=42, offs=51) -- 1196(line=42, offs=52)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1160(line=41, offs=51) -- 1161(line=41, offs=52)
 */
 ATSifnthen(ATSCKpat_int(arg0, ATSPMVint(1))) { ATSINSgoto(__atstmplab12) ; } ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1269(line=44, offs=12) -- 1269(line=44, offs=12)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1234(line=43, offs=12) -- 1234(line=43, offs=12)
 */
 ATSINSlab(__atstmplab11):
 /*
@@ -2006,7 +2006,7 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1273(line=44, offs=16) -- 1285(line=44, offs=28)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1238(line=43, offs=16) -- 1250(line=43, offs=28)
 */
 ATSINSmove(tmpret48, ATSCNTRB_056_HX_056_intinf_vt__intinf_make_int__1__5(env0)) ;
 
@@ -2014,15 +2014,15 @@
 
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1297(line=45, offs=11) -- 1298(line=45, offs=12)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1262(line=44, offs=11) -- 1263(line=44, offs=12)
 */
 ATSINSlab(__atstmplab12):
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1195(line=42, offs=51) -- 1196(line=42, offs=52)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1160(line=41, offs=51) -- 1161(line=41, offs=52)
 */
 ATSifnthen(ATSCKpat_int(arg0, ATSPMVint(2))) { ATSINSgoto(__atstmplab14) ; } ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1298(line=45, offs=12) -- 1298(line=45, offs=12)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1263(line=44, offs=12) -- 1263(line=44, offs=12)
 */
 ATSINSlab(__atstmplab13):
 /*
@@ -2032,29 +2032,29 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1316(line=45, offs=30) -- 1339(line=45, offs=53)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1281(line=44, offs=30) -- 1304(line=44, offs=53)
 */
 ATSINSmove(tmp59, atspre_g1int_sub_int(env0, ATSPMVi0nt(1))) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1316(line=45, offs=30) -- 1339(line=45, offs=53)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1281(line=44, offs=30) -- 1304(line=44, offs=53)
 */
 ATSINSmove(tmp58, atspre_g1int_mul_int(tmp59, env0)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1316(line=45, offs=30) -- 1339(line=45, offs=53)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1281(line=44, offs=30) -- 1304(line=44, offs=53)
 */
 ATSINSmove(tmp53, ATSCNTRB_056_HX_056_intinf_vt__intinf_make_int__1__6(tmp58)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1302(line=45, offs=16) -- 1340(line=45, offs=54)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1267(line=44, offs=16) -- 1305(line=44, offs=54)
 */
 ATSINSmove(tmpret48, ATSPMVcastfn(castvwtp0, atstkind_type(atstype_ptrk), tmp53)) ;
 ATSbranch_end()
 
 ATSbranch_beg()
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1352(line=46, offs=12) -- 1352(line=46, offs=12)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1317(line=45, offs=12) -- 1317(line=45, offs=12)
 */
 ATSINSlab(__atstmplab14):
 /*
@@ -2064,33 +2064,33 @@
 ibranch-mbody:
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1357(line=46, offs=17) -- 1498(line=51, offs=12)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1322(line=45, offs=17) -- 1463(line=50, offs=12)
 */
 /*
 letpush(beg)
 */
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1394(line=47, offs=34) -- 1399(line=47, offs=39)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1359(line=46, offs=34) -- 1364(line=46, offs=39)
 */
 ATSINSmove(tmp61, atspre_g1int_sub_int(arg0, ATSPMVi0nt(1))) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1379(line=47, offs=19) -- 1400(line=47, offs=40)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1344(line=46, offs=19) -- 1365(line=46, offs=40)
 */
 ATSINSmove(tmp60, numerator_loop_22(env0, tmp61)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1438(line=48, offs=38) -- 1443(line=48, offs=43)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1403(line=47, offs=38) -- 1408(line=47, offs=43)
 */
 ATSINSmove(tmp66, atspre_g1int_add_int(env0, ATSPMVi0nt(1))) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1438(line=48, offs=38) -- 1447(line=48, offs=47)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1403(line=47, offs=38) -- 1412(line=47, offs=47)
 */
 ATSINSmove(tmp65, atspre_g1int_sub_int(tmp66, arg0)) ;
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1419(line=48, offs=19) -- 1448(line=48, offs=48)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1384(line=47, offs=19) -- 1413(line=47, offs=48)
 */
 ATSINSmove(tmp62, ATSCNTRB_056_HX_056_intinf_vt__mul_intinf0_int__7__3(tmp60, tmp65)) ;
 
@@ -2099,11 +2099,11 @@
 */
 
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1470(line=50, offs=11) -- 1485(line=50, offs=26)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1435(line=49, offs=11) -- 1450(line=49, offs=26)
 */
 ATSINSmove(tmpret48, ATSPMVcastfn(castvwtp0, atstkind_type(atstype_ptrk), tmp62)) ;
 /*
-emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1357(line=46, offs=17) -- 1498(line=51, offs=12)
+emit_instr: loc0 = /home/vanessa/programming/haskell/done/fast-arithmetic/ats-src/combinatorics.dats: 1322(line=45, offs=17) -- 1463(line=50, offs=12)
 */
 /*
 INSletpop()
diff --git a/cbits/number-theory.c b/cbits/number-theory.c
--- a/cbits/number-theory.c
+++ b/cbits/number-theory.c
@@ -1,7 +1,7 @@
 /*
 **
 ** The C code is generated by [ATS/Postiats-0-3-8]
-** The starting compilation time is: 2018-1-6:  1h:14m
+** The starting compilation time is: 2018-1-6: 19h:39m
 **
 */
 
diff --git a/cbits/numerics.c b/cbits/numerics.c
--- a/cbits/numerics.c
+++ b/cbits/numerics.c
@@ -1,7 +1,7 @@
 /*
 **
 ** The C code is generated by [ATS/Postiats-0-3-8]
-** The starting compilation time is: 2018-1-6:  1h:14m
+** The starting compilation time is: 2018-1-6: 19h:39m
 **
 */
 
diff --git a/fast-arithmetic.cabal b/fast-arithmetic.cabal
--- a/fast-arithmetic.cabal
+++ b/fast-arithmetic.cabal
@@ -1,5 +1,5 @@
 name:                fast-arithmetic
-version:             0.1.1.1
+version:             0.1.1.2
 synopsis:            Fast number-theoretic functions.
 description:         Fast number-theoretic code with a high level of safety guaranteed by ATS.
 homepage:            https://github.com/vmchale/fast-arithmetic#readme
@@ -48,9 +48,11 @@
                      , Numeric.Integer
                      , Numeric.NumberTheory
                      , Numeric.Combinatorics
+                     , Data.GMP
   other-modules:       Numeric.Common
   build-depends:       base >= 4.7 && < 5
                      , composition-prelude
+                     , recursion-schemes
   default-language:    Haskell2010
   if flag(development)
     if impl(ghc >= 8.0)
diff --git a/src/Data/GMP.hs b/src/Data/GMP.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/GMP.hs
@@ -0,0 +1,48 @@
+{-# LANGUAGE CPP #-}
+
+-- | This module defines a storable instance for GMP's integer type.
+
+module Data.GMP ( GMPInt (..)
+                , gmpToInteger
+                ) where
+
+#if __GLASGOW_HASKELL__ <= 784
+import           Control.Applicative
+#endif
+import           Data.Functor.Foldable
+import           Data.Word
+import           Foreign.Marshal.Array
+import           Foreign.Ptr
+import           Foreign.Storable
+
+-- | The GMP integer type holds information about array size as well as
+-- a pointer to an array.
+data GMPInt = GMPInt { _mp_alloc :: Word32, _mp_size :: Word32, _mp_d :: Ptr Word64 }
+
+wordWidth :: Int
+wordWidth = sizeOf (undefined :: Word32)
+
+ptrWidth :: Int
+ptrWidth = sizeOf (undefined :: Ptr Word64)
+
+gmpToList :: GMPInt -> IO [Word64]
+gmpToList (GMPInt _ s aptr) = peekArray (fromIntegral s) aptr
+
+wordListToInteger :: [Word64] -> Integer
+wordListToInteger = cata a where
+    a Nil         = 0
+    a (Cons x xs) = fromIntegral x + (2 ^ (64 :: Integer)) * xs
+
+-- | Convert a GMPInt to Haskell's 'Integer' type.
+gmpToInteger :: GMPInt -> IO Integer
+gmpToInteger = fmap wordListToInteger . gmpToList
+
+instance Storable GMPInt where
+    sizeOf _ = 2 * wordWidth + ptrWidth
+    alignment _ = gcd wordWidth ptrWidth
+    peek ptr = GMPInt <$> peekByteOff ptr 0 <*> peekByteOff ptr wordWidth <*> peekByteOff ptr (wordWidth * 2)
+    poke ptr (GMPInt a s d) =
+        pokeByteOff ptr 0 a >>
+        pokeByteOff ptr wordWidth s >>
+        pokeByteOff ptr (wordWidth * 2) d
+
diff --git a/src/Numeric/Combinatorics.hs b/src/Numeric/Combinatorics.hs
--- a/src/Numeric/Combinatorics.hs
+++ b/src/Numeric/Combinatorics.hs
@@ -1,44 +1,14 @@
-{-# LANGUAGE CPP #-}
-
 -- | This provides a few facilities for working with common combinatorial
 -- functions.
 module Numeric.Combinatorics ( factorial
                              , choose
                              ) where
 
-#if __GLASGOW_HASKELL__ <= 784
-import           Control.Applicative
-#endif
 import           Control.Composition
-import           Data.Word
+import           Data.GMP
 import           Foreign.C
-import           Foreign.Marshal.Array
 import           Foreign.Ptr
 import           Foreign.Storable
-
-data GMPInt = GMPInt { _mp_alloc :: Word32, _mp_size :: Word32, _mp_d :: Ptr Word64 }
-
-wordWidth :: Int
-wordWidth = sizeOf (undefined :: Word32)
-
-ptrWidth :: Int
-ptrWidth = sizeOf (undefined :: Ptr Word64)
-
-gmpToList :: GMPInt -> IO [Word64]
-gmpToList (GMPInt a _ aptr) = peekArray (fromIntegral a) aptr
-
-wordListToInteger :: [Word64] -> Integer
-wordListToInteger []     = 0
-wordListToInteger (x:xs) = fromIntegral x + (2 ^ (64 :: Integer)) * wordListToInteger xs
-
-gmpToInteger :: GMPInt -> IO Integer
-gmpToInteger = fmap wordListToInteger . gmpToList
-
-instance Storable GMPInt where
-    sizeOf _ = 2 * wordWidth + ptrWidth
-    alignment _ = gcd wordWidth ptrWidth
-    peek ptr = GMPInt <$> peekByteOff ptr 0 <*> peekByteOff ptr wordWidth <*> peekByteOff ptr (wordWidth * 2)
-    poke = undefined
 
 foreign import ccall unsafe factorial_ats :: CInt -> Ptr GMPInt
 foreign import ccall unsafe choose_ats :: CInt -> CInt -> Ptr GMPInt
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,3 +1,4 @@
+import           Data.List             (zipWith4)
 import           Numeric.Combinatorics
 import           Numeric.Integer
 import           Numeric.NumberTheory
@@ -11,29 +12,39 @@
         go :: Int -> Int -> Integer
         go m n = fromIntegral m ^ (fromIntegral n :: Integer)
 
+agree :: (Eq a) => String -> (Int -> a) -> (Int -> a) -> SpecWith ()
+agree s f g = describe s $
+    prop "should agree with the pure Haskell function" $
+        \n -> n < 1 || f n == g n
+
+check :: (Eq a, Show a) => String -> (Int -> IO a) -> (Integer -> a) -> Int -> SpecWith ()
+check s f g n = describe s $
+    it ("should work for n=" ++ show n) $
+        f n >>= (`shouldBe` g (fromIntegral n))
+
 main :: IO ()
 main = hspec $ parallel $ do
-    describe "isPrime" $
-        prop "should agree with the pure Haskell function" $
-            \x -> x < 1 || isPrime x == hsIsPrime x
-    describe "totient" $
-        prop "should agree with the pure Haskell function" $
-            \m -> m < 1 || totient m == hsTotient m
+
+    sequence_ $ zipWith3 agree
+        ["totient", "tau", "littleOmega"]
+        [totient, tau, littleOmega]
+        [hsTotient, hsTau, hsLittleOmega]
+
+    sequence_ $ zipWith3 agree
+        ["isPrime", "isPerfect"]
+        [isPrime, isPerfect]
+        [hsIsPrime, hsIsPerfect]
+
     describe "totient" $
         prop "should be equal to m-1 for m prime" $
             \m -> m < 1 || not (isPrime m) || totient m == m - 1
     describe "totient" $
         prop "should satisfy Fermat's little theorem" $
             \a m -> a < 1 || m < 2 || gcd a m /= 1 || tooBig a m || (a ^ totient m) `mod` m == 1
-    describe "tau" $
-        prop "should agree with the pure Haskell function" $
-            \n -> n < 1 || tau n == hsTau n
-    describe "littleOmega" $
-        prop "should agree with the pure Haskell function" $
-            \n -> n < 1 || littleOmega n == hsLittleOmega n
-    describe "isPerfect" $
-        prop "should agree with the pure Haskell function" $
-            \n -> n < 1 || isPerfect n == hsIsPerfect n
-    describe "factorial" $
-        it "should work on a slightly large number" $
-            factorial 3141 >>= (`shouldBe` hsFactorial 3141)
+
+    -- TODO property test w/ recurrence relations?
+    sequence_ $ zipWith4 check
+        ["factorial", "choose"]
+        [factorial, choose 101]
+        [hsFactorial, hsChoose 101]
+        [3141, 16]
