重构 Haskell 单子代码以避免复制粘贴
Refactor Haskell monadic code to avoid copy-paste
我在 Haskell 中使用 ST monad 编写了以下代码并且它有效。我唯一的问题是如何避免下面代码中显示的复制粘贴。当我尝试重构代码时,出现了我无法完全理解的编译器错误。有没有办法避免在下面的代码中复制粘贴。我想知道,是否可以将处理 start_1 和 start_2(截至目前 copy/paste)的代码重构为另一个辅助函数。
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)
当我尝试将上面的复制粘贴代码移动到使用 'let' 绑定创建的本地函数(名为 sieve_factors)时收到的错误消息是:
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 ...;
.... }’
编译器告诉你
Use FlexibleContexts to permit this
这意味着将 FlexibleContexts
language extension. You can do this by adding a LANGUAGE
pragma 启用到源文件的顶部
{-# LANGUAGE FlexibleContexts #-}
我在 Haskell 中使用 ST monad 编写了以下代码并且它有效。我唯一的问题是如何避免下面代码中显示的复制粘贴。当我尝试重构代码时,出现了我无法完全理解的编译器错误。有没有办法避免在下面的代码中复制粘贴。我想知道,是否可以将处理 start_1 和 start_2(截至目前 copy/paste)的代码重构为另一个辅助函数。
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)
当我尝试将上面的复制粘贴代码移动到使用 'let' 绑定创建的本地函数(名为 sieve_factors)时收到的错误消息是:
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 ...;
.... }’
编译器告诉你
Use FlexibleContexts to permit this
这意味着将 FlexibleContexts
language extension. You can do this by adding a LANGUAGE
pragma 启用到源文件的顶部
{-# LANGUAGE FlexibleContexts #-}