从简单的代码开始,慢慢的迭代,经过几次变得抽象复杂起来。
本文将以定时任务系统 worker 的演化过程来说明代码是如何变得抽象。
第一次迭代
module Worker2 where
import Prelude
import Effect (Effect)
import Effect.Aff (Aff, delay, launchAff_)
import Effect.Aff.Class (liftAff)
import Data.Time.Duration (Milliseconds (..))
import Periodic.Worker (addFunc, done, name, runWorkerT, work)
periodicHost :: {port :: Int, host :: String}
periodicHost = {port: 5000, host: "127.0.0.1"}
someFunc1 :: String -> Aff Unit
someFunc1 _ = delay (Milliseconds 1000.0)
main :: Effect Unit
main = launchAff_ $ runWorkerT launchAff_ periodicHost do
addFunc "func1" do
n <- name
liftAff $ someFunc1 n
done
work 10
第二次迭代
module Worker2 where
import Prelude
import Effect (Effect)
import Effect.Aff (Aff, delay, launchAff_)
import Effect.Aff.Class (liftAff)
import Data.Time.Duration (Milliseconds (..))
import Periodic.Worker (addFunc, done, name, runWorkerT, work, JobT)
periodicHost :: {port :: Int, host :: String}
periodicHost = {port: 5000, host: "127.0.0.1"}
someFunc1 :: String -> Aff Unit
someFunc1 _ = delay (Milliseconds 1000.0)
someFunc2 :: String -> Aff Unit
someFunc2 _ = delay (Milliseconds 1000.0)
affTask :: (String -> Aff Unit) -> JobT Aff Unit
affTask f = do
n <- name
liftAff $ f n
done
main :: Effect Unit
main = launchAff_ $ runWorkerT launchAff_ periodicHost do
addFunc "func1" $ affTask someFunc1
addFunc "func2" $ affTask someFunc2
work 10
func1
和 func2
是差不多类似的函数所以我们抽象出 affTask
。
第三次迭代
affTask
目前只能适用 String -> Aff Unit
类型的函数,
但实际上我们会有很多相类似的函数,如 Int -> Aff Unit
。
我们需要对 affTask
进行改造,让它适用。
module Worker2 where
import Prelude
import Effect (Effect)
import Effect.Aff (Aff, delay, launchAff_)
import Effect.Aff.Class (liftAff)
import Data.Time.Duration (Milliseconds (..))
import Periodic.Worker (addFunc, done, name, runWorkerT, work, JobT)
import Data.Maybe (Maybe (..))
import Data.Int (fromString)
periodicHost :: {port :: Int, host :: String}
periodicHost = {port: 5000, host: "127.0.0.1"}
someFunc1 :: String -> Aff Unit
someFunc1 _ = delay (Milliseconds 1000.0)
someFunc2 :: String -> Aff Unit
someFunc2 _ = delay (Milliseconds 1000.0)
someFunc3 :: Int -> Aff Unit
someFunc3 _ = delay (Milliseconds 1000.0)
mkAffTask :: forall a. (String -> Maybe a) -> (a -> Aff Unit) -> JobT Aff Unit
mkAffTask mk f = do
n <- mk <$> name
case n of
Nothing -> done
Just n0 -> do
liftAff $ f n0
done
affTask :: (String -> Aff Unit) -> JobT Aff Unit
affTask = mkAffTask Just
affTaskI :: (Int -> Aff Unit) -> JobT Aff Unit
affTaskI = mkAffTask fromString
main :: Effect Unit
main = launchAff_ $ runWorkerT launchAff_ periodicHost do
addFunc "func1" $ affTask someFunc1
addFunc "func2" $ affTask someFunc2
addFunc "func3" $ affTaskI someFunc3
work 10
mkAffTask
就是用来构造 affTask
和 affTaskI
这两个函数。
第四次迭代
如果我们的函数需要在过一段时间在执行一个呢?
module Worker2 where
import Prelude
import Effect (Effect)
import Effect.Aff (Aff, delay, launchAff_)
import Effect.Aff.Class (liftAff)
import Data.Time.Duration (Milliseconds (..))
import Periodic.Worker (addFunc, done, name, runWorkerT, work, JobT, schedLater)
import Data.Maybe (Maybe (..))
import Data.Int (fromString)
periodicHost :: {port :: Int, host :: String}
periodicHost = {port: 5000, host: "127.0.0.1"}
someFunc1 :: String -> Aff Unit
someFunc1 _ = delay (Milliseconds 1000.0)
someFunc2 :: String -> Aff Unit
someFunc2 _ = delay (Milliseconds 1000.0)
someFunc3 :: Int -> Aff Unit
someFunc3 _ = delay (Milliseconds 1000.0)
someFunc4 :: String -> Aff (Maybe Int)
someFunc4 _ = pure $ Just 10
someFunc5 :: Int -> Aff (Maybe Int)
someFunc5 _ = pure Nothing
mkAffTask :: forall a b. (b -> JobT Aff Unit) -> (String -> Maybe a) -> (a -> Aff b) -> JobT Aff Unit
mkAffTask finish mk f = do
n <- mk <$> name
case n of
Nothing -> done
Just n0 -> do
r <- liftAff $ f n0
finish r
maybeLater :: Maybe Int -> JobT Aff Unit
maybeLater Nothing = done
maybeLater (Just v) = schedLater v
affTask :: (String -> Aff Unit) -> JobT Aff Unit
affTask = mkAffTask (const done) Just
affTaskI :: (Int -> Aff Unit) -> JobT Aff Unit
affTaskI = mkAffTask (const done) fromString
affLaterTask :: (String -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTask = mkAffTask maybeLater Just
affLaterTaskI :: (Int -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTaskI = mkAffTask maybeLater fromString
main :: Effect Unit
main = launchAff_ $ runWorkerT launchAff_ periodicHost do
addFunc "func1" $ affTask someFunc1
addFunc "func2" $ affTask someFunc2
addFunc "func3" $ affTaskI someFunc3
addFunc "func4" $ affLaterTask someFunc4
addFunc "func5" $ affLaterTaskI someFunc5
work 10
第五次迭代
如果我们的数据不是从 name
来获取呢?
module Worker2 where
import Prelude
import Effect (Effect)
import Effect.Aff (Aff, delay, launchAff_)
import Effect.Aff.Class (liftAff)
import Data.Time.Duration (Milliseconds (..))
import Periodic.Worker (addFunc, done, name, runWorkerT, work, JobT, schedLater, workload)
import Data.Maybe (Maybe (..))
import Data.Int (fromString)
periodicHost :: {port :: Int, host :: String}
periodicHost = {port: 5000, host: "127.0.0.1"}
someFunc1 :: String -> Aff Unit
someFunc1 _ = delay (Milliseconds 1000.0)
someFunc2 :: String -> Aff Unit
someFunc2 _ = delay (Milliseconds 1000.0)
someFunc3 :: Int -> Aff Unit
someFunc3 _ = delay (Milliseconds 1000.0)
someFunc4 :: String -> Aff (Maybe Int)
someFunc4 _ = pure $ Just 10
someFunc5 :: Int -> Aff (Maybe Int)
someFunc5 _ = pure Nothing
mkAffTask :: forall a b. (b -> JobT Aff Unit) -> (String -> Maybe a) -> JobT Aff String -> (a -> Aff b) -> JobT Aff Unit
mkAffTask finish mk get f = do
n <- mk <$> get
case n of
Nothing -> done
Just n0 -> do
r <- liftAff $ f n0
finish r
maybeLater :: Maybe Int -> JobT Aff Unit
maybeLater Nothing = done
maybeLater (Just v) = schedLater v
affTask_ :: JobT Aff String -> (String -> Aff Unit) -> JobT Aff Unit
affTask_ = mkAffTask (const done) Just
affTask :: (String -> Aff Unit) -> JobT Aff Unit
affTask = affTask_ name
affTaskI_ :: JobT Aff String -> (Int -> Aff Unit) -> JobT Aff Unit
affTaskI_ = mkAffTask (const done) fromString
affTaskI :: (Int -> Aff Unit) -> JobT Aff Unit
affTaskI = affTaskI_ name
affLaterTask_ :: JobT Aff String -> (String -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTask_ = mkAffTask maybeLater Just
affLaterTask :: (String -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTask = affLaterTask_ name
affLaterTaskI_ :: JobT Aff String -> (Int -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTaskI_ = mkAffTask maybeLater fromString
affLaterTaskI :: (Int -> Aff (Maybe Int)) -> JobT Aff Unit
affLaterTaskI = affLaterTaskI_ name
main :: Effect Unit
main = launchAff_ $ runWorkerT launchAff_ periodicHost do
addFunc "func1" $ affTask someFunc1
addFunc "func2" $ affTask someFunc2
addFunc "func3" $ affTaskI someFunc3
addFunc "func4" $ affLaterTask someFunc4
addFunc "func5" $ affLaterTaskI someFunc5
addFunc "func6" $ affTask_ workload someFunc1
addFunc "func7" $ affTaskI_ workload someFunc3
addFunc "func8" $ affLaterTask_ workload someFunc4
addFunc "func9" $ affLaterTaskI_ workload someFunc5
work 10
总结
经过五次迭代我们构造出一个非常复杂的 mkAffTask
函数。
相关资源:
网友评论