N-queens.agda 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. -- An Agda implementation of the n queens program from the nofib
  2. -- benchmark. Very inefficient, uses unary natural numbers instead of
  3. -- machine integers.
  4. module N-queens where
  5. open import Category.Monad
  6. open import Coinduction
  7. open import Data.Bool hiding (_≟_)
  8. open import Data.Char hiding (_≟_)
  9. open import Data.Fin using (#_)
  10. open import Data.Digit
  11. open import Data.Integer as Z using (+_; _⊖_)
  12. open import Data.List as List
  13. open import Data.Maybe as Maybe
  14. open import Data.Nat
  15. open import Data.Nat.Show
  16. open import Data.String as String using (String)
  17. open import Data.Unit hiding (_≟_)
  18. open import Function
  19. open import IO using (IO)
  20. import IO.Primitive as Primitive
  21. open import Relation.Nullary.Decidable
  22. ------------------------------------------------------------------------
  23. -- Things missing from the standard library
  24. take_[_…] : ℕ → ℕ → List ℕ
  25. take zero [ n …] = []
  26. take suc k [ n …] = n ∷ take k [ suc n …]
  27. [_…_] : ℕ → ℕ → List ℕ
  28. [ m … n ] with compare m n
  29. [ .(suc (n + k)) … n ] | greater .n k = []
  30. [ m … .m ] | equal .m = [ m ]
  31. [ m … .(suc (m + k)) ] | less .m k = take (2 + k) [ m …]
  32. guard : Bool → List ⊤
  33. guard true = [ _ ]
  34. guard false = []
  35. postulate
  36. getArgs′ : Primitive.IO (List String)
  37. {-# FOREIGN GHC System.Environment #-}
  38. {-# COMPILE GHC getArgs′ = System.Environment.getArgs #-}
  39. getArgs : IO (List String)
  40. getArgs = lift getArgs′
  41. where open IO
  42. read : List Char → Maybe ℕ
  43. read [] = nothing
  44. read ds = fromDigits ∘ reverse <$> mapM Maybe.monad charToDigit ds
  45. where
  46. open RawMonad Maybe.monad
  47. charToDigit : Char → Maybe (Digit 10)
  48. charToDigit '0' = just (# 0)
  49. charToDigit '1' = just (# 1)
  50. charToDigit '2' = just (# 2)
  51. charToDigit '3' = just (# 3)
  52. charToDigit '4' = just (# 4)
  53. charToDigit '5' = just (# 5)
  54. charToDigit '6' = just (# 6)
  55. charToDigit '7' = just (# 7)
  56. charToDigit '8' = just (# 8)
  57. charToDigit '9' = just (# 9)
  58. charToDigit _ = nothing
  59. ------------------------------------------------------------------------
  60. -- The main program
  61. nsoln : ℕ → ℕ
  62. nsoln nq = length (gen nq)
  63. where
  64. open RawMonad List.monad
  65. safe : ℕ → ℕ → List ℕ → Bool
  66. safe x d [] = true
  67. safe x d (q ∷ l) = not ⌊ x ≟ q ⌋ ∧
  68. not ⌊ x ≟ q + d ⌋ ∧
  69. not ⌊ + x Z.≟ q ⊖ d ⌋ ∧
  70. -- Equivalent to previous line, because x ≥ 1:
  71. -- not ⌊ x ≟ q ∸ d ⌋ ∧
  72. safe x (1 + d) l
  73. gen : ℕ → List (List ℕ)
  74. gen zero = [ [] ]
  75. gen (suc n) =
  76. gen n >>= λ b →
  77. [ 1 … nq ] >>= λ q →
  78. guard (safe q 1 b) >>
  79. return (q ∷ b)
  80. main = run (♯ getArgs >>= λ arg → ♯ main′ arg)
  81. where
  82. open IO
  83. main′ : List String → IO ⊤
  84. main′ (arg ∷ []) with read (String.toList arg)
  85. ... | just n = putStrLn (show (nsoln n))
  86. ... | nothing = return _
  87. main′ _ = return _