728x90
함수 자신을 직접 또는 간접적으로 호출하는 함수를 재귀함수라고 한다.
정수의 팩토리얼(N!) 을 계산하는 것이 전형적인 재귀의 예시이다.
그럼 이를 하스켈로 작성해보자. 그리고 그 타입이 무엇인지 알아보자.
1 2 | factorial n | n == 0 = 1 | otherwise = n * factorial (n-1) | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | *Main> :load factorial [1 of 1] Compiling Main ( factorial.hs, interpreted ) Ok, modules loaded: Main. *Main> :type factorial factorial :: (Eq a, Num a) => a -> a *Main> factorial 40 815915283247897734345611269596115894272000000000 it :: (Eq a, Num a) => a | cs |
재귀 연산을 수동으로 추적하는 방법은 call 에 밑줄을 친 다음, 해당 call 을 textual expansion 을 가지고 다시 작성하는 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | factorial 4 4 * factorial 3 4 * 3 * factorial 2 4 * 3 * 2 * factorial 1 4 * 3 * 2 * 1 * factorial 0 4 * 3 * 2 * 1 * 1 | cs |
나머지가 1이 될 때까지 반복적으로 나누는 연산을 생각해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 | *Main> 28 `quot` 3 9 it :: Integral a => a *Main> it `quot` 3 3 it :: Integral a => a *Main> it `quot` 3 1 it :: Integral a => a | cs |
나머지가 1이 될 때까지 몇 번 나눠야 하는지를 계산하는 재귀함수 numDivs 를 작성해보자.
1 2 | numDivs divisor x | (x `quot` divisor) < 1 = 0 | otherwise = 1 + numDivs divisor (x `quot` divisor) | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 | *Main> :load numdiv [1 of 1] Compiling Main ( numdiv.hs, interpreted ) Ok, modules loaded: Main. *Main> numDivs 3 28 3 it :: Num a1 => a1 *Main> numDivs 2 7 2 it :: Num a1 => a1 | cs |
타입은 무엇인가?
1 2 3 4 | *Main> :t numDivs numDivs :: (Integral a, Num a1) => a -> a -> a1 | cs |
그러면 numDivs 2 3.4 은 작동하는가?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | *Main> numDivs 2 3.4 <interactive>:64:1: Could not deduce (Integral a0) arising from a use of ‘numDivs’ from the context (Num a1) bound by the inferred type of it :: Num a1 => a1 at <interactive>:64:1-13 The type variable ‘a0’ is ambiguous Note: there are several potential instances: instance Integral Integer -- Defined in ‘GHC.Real’ instance Integral Int -- Defined in ‘GHC.Real’ instance Integral Word -- Defined in ‘GHC.Real’ In the expression: numDivs 2 3.4 In an equation for ‘it’: it = numDivs 2 3.4 <interactive>:64:9: Could not deduce (Num a0) arising from the literal ‘2’ from the context (Num a1) bound by the inferred type of it :: Num a1 => a1 at <interactive>:64:1-13 The type variable ‘a0’ is ambiguous Note: there are several potential instances: instance Integral a => Num (GHC.Real.Ratio a) -- Defined in ‘GHC.Real’ instance Num Integer -- Defined in ‘GHC.Num’ instance Num Double -- Defined in ‘GHC.Float’ ...plus three others In the first argument of ‘numDivs’, namely ‘2’ In the expression: numDivs 2 3.4 In an equation for ‘it’: it = numDivs 2 3.4 <interactive>:64:11: Could not deduce (Fractional a0) arising from the literal ‘3.4’ from the context (Num a1) bound by the inferred type of it :: Num a1 => a1 at <interactive>:64:1-13 The type variable ‘a0’ is ambiguous Note: there are several potential instances: instance Integral a => Fractional (GHC.Real.Ratio a) -- Defined in ‘GHC.Real’ instance Fractional Double -- Defined in ‘GHC.Float’ instance Fractional Float -- Defined in ‘GHC.Float’ In the second argument of ‘numDivs’, namely ‘3.4’ In the expression: numDivs 2 3.4 In an equation for ‘it’: it = numDivs 2 3.4 *Main> | cs |
아래와 같이 2개의 어플리케이션에 식별자를 붙여보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | *Main> let f = numDivs 2 f :: (Integral a, Num a1) => a -> a1 *Main> let g = numDivs 10 g :: (Integral a, Num a1) => a -> a1 *Main> f 9 3 it :: Num a1 => a1 *Main> g 1001 3 it :: Num a1 => a1 | cs |
f 나 g 보다 좀 더 직관적인 이름으로 바꿔보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | *Main> let floor_log2 = numDivs 2 floor_log2 :: (Integral a, Num a1) => a -> a1 *Main> floor_log2 1000 9 it :: Num a1 => a1 *Main> let floor_log10 = numDivs 10 floor_log10 :: (Integral a, Num a1) => a -> a1 *Main> floor_log10 1000 3 it :: Num a1 => a1 | cs |
728x90
'프로그래밍 Programming' 카테고리의 다른 글
Functional Programming with Haskell - Comparing lists, Lists of Lists (0) | 2018.04.19 |
---|---|
Functional Programming with Haskell - Lists basics (0) | 2018.04.17 |
Functional Programming with Haskell - Haskell's if-else (0) | 2018.04.16 |
Functional Programming with Haskell -Guards (0) | 2018.04.13 |
Functional Programming with Haskell - Function/operator equivalence CSC 372 (0) | 2018.03.31 |