0

I have written the following code in Haskell using ST monad and it works. My only question is how do I avoid the copy-paste shown in the code below. When I tried to refactor the code, I got compiler errors I could not fully understand. Is there a way to avoid the copy-paste in the code below. I would like to know, if I could refactor the code that processes for start_1 and start_2 (as of now copy/paste) to another helper function.

import qualified Control.Monad as CM
import qualified Control.Monad.ST as CMST
import qualified Data.Array as A
import qualified Data.Array.Unboxed as AU
import qualified Data.Array.ST as AST


prime_factors :: Int -> Int -> [(Int, Int)] -> A.Array Int [(Int, Int)]
prime_factors a_low a_high prms_sqrts = AST.runSTArray $ do
  pfs <- AST.newArray (a_low, a_high) [] :: CMST.ST s (AST.STArray s Int [(Int, Int)])
  as <- AST.newArray (a_low, a_high) 0 :: CMST.ST s (AST.STArray s Int Int)
  CM.forM_ [a_low..a_high] $ \i -> do
    AST.writeArray as i ((i * i) + 1)
  CM.forM_ (takeWhile (\(prm, _) -> prm <= (a_high + 1)) prms_sqrts) $ \(prm, sqr_rt) -> do
    let (q, r) = a_low `divMod` prm
    let start_1 = a_low + sqr_rt - r
    -- !!!! CODE TO DO SOME PROCESSING FOR start_1 !!!!!
    CM.forM_ (takeWhile (<= a_high) [start_1 + (x * prm) | x <- [0..]]) $ \i -> do
      a_i <- AST.readArray as i
      let (a_i', mul) = remove_factor a_i prm 0
      CM.when (mul > 0) $ do
        AST.writeArray as i a_i'
        pfs_i <- AST.readArray pfs i
        AST.writeArray pfs i ((prm, mul) : pfs_i)
    let start_2 = a_low + (prm - sqr_rt) - r
    -- !!!! COPY-PASTE ABOVE CODE TO PROCESS start_2 !!!!
    CM.forM_ (takeWhile (<= a_high) [start_2 + (x * prm) | x <- [0..]]) $ \i -> do
      a_i <- AST.readArray as i
      let (a_i', mul) = remove_factor a_i prm 0
      CM.when (mul > 0) $ do
        AST.writeArray as i a_i'
        pfs_i <- AST.readArray pfs i
        AST.writeArray pfs i ((prm, mul) : pfs_i)
  CM.forM_ [a_low..a_high] $ \i -> do
    a_i <- AST.readArray as i
    CM.when (a_i > 1) $ do
      pfs_i <- AST.readArray pfs i
      AST.writeArray pfs i ((a_i, 1) : pfs_i)
  return pfs
  where remove_factor m p mul
          | m `mod` p == 0 = remove_factor (m `div` p) p (mul + 1)
          | otherwise = (m, mul)

The error message I get when I try to move the above copy-paste code to a local function (named sieve_factors) created with a 'let' binding is:

vamsi@vamsi-laptop:~/learn/project_euler/129_to_256/problem_224$ ghc --make -O -i../.. problem_224.hs
[3 of 3] Compiling Main             ( problem_224.hs, problem_224.o )

problem_224.hs:39:9: error:
    • Non type-variable argument
        in the constraint: AST.MArray (AST.STArray s) Int m
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        sieve_factors :: forall (m :: * -> *).
                         (AST.MArray (AST.STArray s) Int m,
                          AST.MArray (AST.STArray s) [(Int, Int)] m) =>
                         Int -> m ()
      In the expression:
        do { let sieve_factors start = ...;
             let (q, r) = a_low `divMod` prm;
             let start_1 = a_low + sqr_rt - r;
             sieve_factors start_1;
             .... }
      In the second argument of ‘($)’, namely
        ‘\ (prm, sqr_rt)
           -> do { let ...;
                   let ...;
                   .... }’
4

1 回答 1

3

编译器告诉你

Use FlexibleContexts to permit this

这意味着启用FlexibleContexts语言扩展。您可以通过在源文件的顶部添加一个LANGUAGE编译指示来做到这一点

{-# LANGUAGE FlexibleContexts #-}
于 2017-08-17T18:23:38.583 回答