2017-11-12 11 views
1

파이썬을 사용하여 내가하고 싶은 것을 설명해 드리겠습니다. (하스켈에서 이것을 작성하고 싶습니다.) 기본적으로, N = 1을 포함하는 D에서 반복 및 D 배의 값을 N/(D)의 바닥을 합산한다재귀 Haskell 함수로 이것을 작성하는 방법은 무엇입니까?

def f(n): 
    s=0 
    for d in range(1,n+1): 
     s+=d*(n//d) 
    return(s) 

:이 기능을 갖는다.

내가 재귀가 필요하다고 생각하는 하스켈에서 이것을하고 싶습니다. 파이썬 상당 :

def f(d, n): 
    if d == 0: return 0 
    else: return d*(n//d) + f(d-1, n) 

다음 내가 f(n, n)으로 함수를 호출 할 것입니다.

이 글을 쓰는 올바른 방법은 무엇입니까?

내 시도 :

f (d n) = if d == 0 then 0 else d * (n//d) + f (d - 1 n) 

편집, 전체 코드 : 당신이 준

main = do 
    input_line <- getLine 
    let n = read input_line :: Int 
    f d n 
     | d == 0 = 0 
     | otherwise = d * (n `div` d) + f (d-1) n 
    putStrLn f n n 
    return() 
+1

,이'''수 FN = 합계 $ 것이다 작성하는 관용적 인 방법을 (: 당신이 합계에서 그것을 끌어와 한 번만 번식 할 수 있도록 첫 번째 n 용어는 d에 의존하지 않는다 \ d -> d * (n'''d)) <$> [1..n + 1]'''. 더 효율적이기 때문에'div' 대신'quot'를 사용합니다. 'd'는 결코 음수가되지 않으므로 똑같이 행동 할 것입니다. 또한'readSthLn _ :: IO()'때문에'read <$> getLine' ('main'의 처음 두 줄)은'readLn'으로 더 잘 쓰여졌고'return()'은 필요 없습니다. – HTNW

+1

비싸지 않게'd * (n // d) == n - n % d'. – chepner

답변

1

예는 거의 정확합니다.

올바른 방법 다음대로 쓰기 : 예상대로 일반 부문은 /으로 수행되는 반면, 하스켈

f d n = if d == 0 then 0 else d * (n `div` d) + f (d-1) n 

정수 나누기는 div 키워드로 이루어집니다.

둘째, 올바른 우선 순위를 보장하는 경우를 제외하고는 함수 인수에 대괄호를 사용할 필요가 없습니다. 위 코드에서 (d-1)에 대괄호가 있어야 하나의 매개 변수임을 나타내고 n은 두 번째 매개 변수입니다.

순수 코드를 작성할 때 마지막으로, 그것은 대신 경우 다른 가드 구문을 사용하여 아래와 같이 일반적 많은 좋네요 : 당신이 경우 다른 사용하는 경우

f d n 
    | d == 0 = 0 
    | otherwise = d * (n `div` d) + f (d-1) n 

, 일반적으로 좋은 생각 여러 줄로 나뉘어 읽기가 조금 쉬워졌습니다.

f d n = if d == 0 
      then 0 
      else d * (n `div` d) + f (d-1) n 

기능에 따라 함수 이름과 매개 변수에 더 나은 이름을 지정하는 것이 좋습니다.

do 블록에서 이것을 호출하는 경우 몇 가지 방법으로 접근 할 수 있습니다.

f d n 
    | d == 0 = 0 
    | otherwise = d * (n `div` d) + f (d-1) n 

main = do 
    input_line <- getLine 
    let n = read input_line :: Int 
     output = f n n 

    print output 

    -- or convert to string manually 

    putStrLn (show output) 

    -- or call without binding to a variable 

    -- $ is sort of like putting brackets around the f n n, so it is one 
    -- parameter to print 
    print $ f n n 

    putStrLn . show $ f n n 

    {- or we can bind the function to a let block - must be double indented 
    let f d n 
      | d == 0 = 0 
      | otherwise = d * (n `div` d) + f (d - 1) n -} 



    return() 

    {- you can also make functions in where blocks 
    where f d n 
     | d == 0 = 0 
     | otherwise = d * (n `div` d) + f (d-1) n -} 
+0

웬일인지 처음에 '|'로 해석 오류가 발생했습니다 – user8926565

+0

@ user8926565 탭으로 들여 쓰기를 했습니까? Whitespace는 haskell의 몇몇 장소에서 중요합니다. – Zpalmtree

+0

전체 코드 – user8926565

0

수정 및 일정한 공간 솔루션입니다 :

f n = sum . map (\d -> d * (n `div` d)) $ [1..n] 
0

첫째, 파이썬 버전에서 루프를 사용하지 않을, 중 :

f n = go 1 0 
    where 
    go d !s | d <= n = go (d + 1) (s + d * (n `div` d)) 
      | otherwise = s 

더 간단한 해결책이다

def f(n): 
    # s=0 
    # for d in range(1,n+1): 
    #  s+=d*(n//d) 
    # return(s) 
    return sum(d*(n//d) for d in range(1, n+1)) 

이것은 하스켈의 자연스러운 접근 방법입니다.

f n = sum [d*(n `div` d) | d <- [1..n]] 

그러나 범위의 각 요소에 대해 곱셈과 나눗셈을 수행하면 비효율적입니다. 대신, 당신이 쓸 수있는 의미

d * (n // d) == n - n % d # Python 
d * (n `div` d) == n - n `mod` d # Haskell 

sum(n - n % d for d in range(1, n+1) # Python 
sum [n - n `mod` d | d <- [1..n]] # Haskell 

당신은 한 단계 더이 걸릴 수 있음을 인식하여 시작; 참고로

n * n - sum(n % d for d in range(1, n+1)) # Python 
n*n - sum [n `mod` d | d <- [1..n]] # Haskell