2017-11-12 11 views
1

私はPythonを使って何をしたいのかを説明します(私はHaskellでこれを書いています)。私はこの機能を持っています。基本的に包括nにD = 1からループし、そしてd n倍/ Dの床の値を合計されこれを再帰的なHaskell関数として書くには?

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

私は再帰が必要だと考えているハスケルでこれをしたいと思っています。 Pythonの同等:

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 =合計$(だろう\ d - > d *(n '' 'd))<$> [1..n + 1]' ''。私は 'div'の代わりに' quot'を使います。これはもっと効率的だからです。 'd'は決して負ではないので、同じ動作をします。また 'read <$> getLine'(別名' main'の最初の2行)は 'readLn'と書かれています。' putStrLn _ :: IO() 'のために' 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キーワードを用いて行われます。

第2に、正しい優先順位を保証する場合を除いて、関数の引数にはカッコを使用する必要はありません。上記のコードでは、それが1つのパラメータであることを示すために(d-1)の角括弧が必要であり、nは2番目のパラメータです。

純粋なコードを書くときに最後に、それは一般的に以下のように、その後、他の代わりの場合はガードの構文を使用して多くのよりよいです:

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タブでインデントしましたか?空白は、haskellのいくつかの場所で重要です。 – Zpalmtree

+0

完全なコードで私の投稿を編集しました – user8926565

0

正しいと一定のスペースソリューションです:

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

もっと簡単な解決策は以下のとおりです。

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

まず、私はPythonのバージョンでループを使用することはありません、次のいずれか

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)) 

これはHaskellの自然なアプローチです。

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用語は、dに依存しない:

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