任何具有一流功能的語言都可以解決這個問題。事實上,你對「高階」的使用是明顯的;必要的抽象確實是一個更高階的函數。這個想法是寫一個函數applyIf
,該函數接受一個布爾(啓用/禁用),一個控制流操作符(實際上只是一個函數)和一個代碼塊(函數域中的任何值)。那麼,如果布爾值爲true,則將運算符/函數應用於塊/值,否則塊/值將運行/返回。這將在代碼中更清晰。
在Haskell,例如,這種格局將是,沒有一個明確的applyIf
,寫成:
example1 = (if applyFilter then when someFilter else id) body
example2 = (if runOnThread then (void . forkIO) else id) . forM_ [1..10] $ \i ->
print i >> threadDelay 1000000 -- threadDelay takes microseconds
這裏,id
僅僅是身份的功能\x -> x
;它總是返回它的參數。因此,(if cond then f else id) x
與f x
相同,如果是cond == True
,則與id x
相同;否則;當然,id x
與x
相同。
然後,你可以考慮此因素模式伸到我們applyIf
組合子:
applyIf :: Bool -> (a -> a) -> a -> a
applyIf True f x = f x
applyIf False _ x = x
-- Or, how I'd probably actually write it:
-- applyIf True = id
-- applyIf False = flip const
-- Note that `flip f a b = f b a` and `const a _ = a`, so
-- `flip const = \_ a -> a` returns its second argument.
example1' = applyIf applyFilter (when someFilter) body
example2' = applyIf runOnThread (void . forkIO) . forM_ [1..10] $ \i ->
print i >> threadDelay 1000000
然後,當然,如果applyIf
一些特定的用途是在您的應用程序的通用模式,你可以在它摘要:
-- Runs its argument on a separate thread if the application is configured to
-- run on more than one thread.
possiblyThreaded action = do
multithreaded <- (> 1) . numberOfThreads <$> getConfig
applyIf multithreaded (void . forkIO) action
example2'' = possiblyThreaded . forM_ [1..10] $ \i ->
print i >> threadDelay 1000000
如上所述,Haskell當然不是唯一能夠表達這種想法的人。例如,這是Ruby的翻譯,但要注意我的Ruby非常生鏽,所以這可能是單一的。 (我歡迎對如何改進的建議。)
def apply_if(use_function, f, &block)
use_function ? f.call(&block) : yield
end
def example1a
do_when = lambda { |&block| if some_filter then block.call() end }
apply_if(apply_filter, do_when) { puts "Hello, world!" }
end
def example2a
apply_if(run_on_thread, Thread.method(:new)) do
(1..10).each { |i| puts i; sleep 1 }
end
end
def possibly_threaded(&block)
apply_if(app_config.number_of_threads > 1, Thread.method(:new), &block)
end
def example2b
possibly_threaded do
(1..10).each { |i| puts i; sleep 1 }
end
end
的一點是相同的,我們結束了,也許-DO-這-事情的邏輯在其自身的功能,然後應用到的相關版塊碼。請注意,這個函數實際上比僅僅處理代碼塊更加通用(正如Haskell類型簽名所表示的那樣)。例如,您也可以編寫abs n = applyIf (n < 0) negate n
來實現絕對值函數。關鍵是要認識到自己的可以被抽象出來,所以像if語句和for循環可以只是函數。而且我們已經知道如何編寫功能!
此外,上述所有代碼都會編譯和/或運行,但您需要一些導入和定義。對於Haskell的例子,你需要的impots
import Control.Applicative -- for (<$>)
import Control.Monad -- for when, void, and forM_
import Control.Concurrent -- for forkIO and threadDelay
與applyFilter
,someFilter
,body
,runOnThread
,numberOfThreads
和getConfig
一些虛假的定義一起:
applyFilter = False
someFilter = False
body = putStrLn "Hello, world!"
runOnThread = True
getConfig = return 4 :: IO Int
numberOfThreads = id
爲Ruby的例子,你將不需要進口和以下類似僞造定義:
def apply_filter; false; end
def some_filter; false; end
def run_on_thread; true; end
class AppConfig
attr_accessor :number_of_threads
def initialize(n)
@number_of_threads = n
end
end
def app_config; AppConfig.new(4); end
不應該是'if(!apply_filter ||過濾器())'? – gilly3 2013-02-20 21:37:20