2013-02-16 4 views
1

때로는 제어 구조 (if, for, ...)가 있으며 조건에 따라 컨트롤 구조를 사용하거나 본문 만 실행하려고합니다. 간단한 예를 들어, 나는 C에서 다음을 수행 할 수 있지만, 그것은 꽤 추한 : 만 런타임에 apply_filter 알고있는 경우 상위 조건문이있는 언어가 있습니까?

#ifdef APPLY_FILTER 
if (filter()) { 
#endif 
    // do something 
#ifdef APPLY_FILTER 
} 
#endif 

또한 작동하지 않습니다. 물론이 경우 코드를 다음과 같이 변경할 수 있습니다.

if (apply_filter && filter()) 

그러나 임의 제어 구조의 일반적인 경우에는 작동하지 않습니다. (저는 좋은 예가 없습니다 만, 최근에 이와 같은 기능을 통해 많은 이점을 얻은 코드가있었습니다.)

구조를 제어하기 위해 조건을 적용 할 수있는 곳이 있습니까 고차 조건부가 있습니까? 의사에서, 위의 예는 다음과 같습니다

<if apply_filter> 
if (filter()) { 
    // ... 
} 

또는 더 복잡한 예제를하는 varable 함수에 랩 코드를 설정하고 스레드로 시작하는 경우 : 사실 (

<if (run_on_thread)> 
    void thread() { 
<endif> 

    for (int i = 0; i < 10; i++) { 
     printf("%d\n", i); 
     sleep(1); 
    } 

<if (run_on_thread)> 
    } 
    start_thread(&thread); 
<endif> 

, 이 예제에서 위와 아래가 동기화되어 있는지 확인하기 위해 메타 조건에 이름을 지정하는 것이 유용 할 것이라고 생각할 수 있습니다.)

LISP의 기능이라고 생각할 수 있습니다. 맞습니까?

+0

그게'if (! apply_filter || 필터())'? – gilly3

답변

2

Common Lisp에서는 if을 다시 정의 할 수 없습니다. 그러나 당신은 Lisp에서 매크로로 자신 만의 제어 구조를 만들어 대신 사용할 수 있습니다.

6

일급 함수를 사용하는 모든 언어가이 문제를 해결할 수 있습니다. 사실, "고차원"을 사용하는 것은 말하고 있습니다. 필요한 추상화는 참으로 고차 함수가 될 것입니다. 이 아이디어는 부울 (활성화/비활성화), 제어 흐름 연산자 (실제로는 함수) 및 코드 블록 (함수 도메인의 모든 값)을 사용하는 함수 applyIf을 작성하는 것입니다. 부울이 참이면 연산자/함수가 블록/값에 적용되고 그렇지 않으면 블록/값이 단지 실행/반환됩니다. 이것은 코드에서 훨씬 더 명확해질 것입니다. 하스켈에서

는, 예를 들어,이 패턴으로 작성, 명시 적 applyIf없는 것 : id 그냥 신원 기능 \x -> x입니다 여기에

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 

; 항상 그 주장을 되 돌린다. 따라서 (if cond then f else id) xcond == True 인 경우 f x과 같으며, 그렇지 않은 경우 id x과 동일합니다. 물론 id xx과 동일합니다.

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의 일부 특정 사용이 응용 프로그램의 일반적인 패턴 인 경우, 당신은 할 수 추상적 위에 :

그럼 당신은 우리의 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 

위에서 언급했듯이 하스켈은 분명히이 아이디어를 표현할 수있는 유일한 사람이 아닙니다. 예를 들어 여기 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-이-것은 논리를 마무리하고 관련 블록에 그 적용입니다 암호.

이 기능은 코드 블록을 작업하는 것보다 실제로 더 일반적이라는 점에 유의하십시오 (하스켈 형식 서명이 표현함). 예를 들어 abs n = applyIf (n < 0) negate n을 작성하여 절대 값 기능을 구현할 수도 있습니다. 핵심은 코드 블록 자체가을 통해 추상화 될 수 있다는 것을 인식하는 것입니다. 따라서 if 문과 for 루프와 같은 것들이 함수 일 수 있습니다. 그리고 우리는 이미 함수를 작성하는 방법을 알고 있습니다!

또한 위의 코드는 모두 컴파일 및 실행되지만 일부 가져 오기 및 정의가 필요합니다. 루비 예를 들어

applyFilter  = False 
someFilter  = False 
body   = putStrLn "Hello, world!" 
runOnThread  = True 
getConfig  = return 4 :: IO Int 
numberOfThreads = id 

, 당신 : 하스켈 예를 들어, applyFilter, someFilter, body, runOnThread, numberOfThreadsgetConfig의 일부 가짜 정의와 함께 impots에게

import Control.Applicative -- for (<$>) 
import Control.Monad  -- for when, void, and forM_ 
import Control.Concurrent -- for forkIO and threadDelay 

이 필요합니다 수입이없고 다음과 같은 유사한 가짜 정의가 필요합니다.

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 
관련 문제