如何将其写为递归Haskell函数?

时间:2017-11-12 17:18:23

标签: haskell recursion syntax sum

我将用Python描述我想做什么(我想在Haskell中编写)。我有这个功能:

f1, t1, Sxx1 = spectrogram(np.diff(rawdata), F_S)
f2, t2, Sxx2 = spectrogram(np.diff(rawdata - noise), F_S)

Sxx_min = np.amin(np.minimum(Sxx1, Sxx2))
Sxx_max = np.amax(np.maximum(Sxx1, Sxx2))

plt.subplot(211)
plt.pcolormesh(t1, f1, Sxx1, vmin=Sxx_min, vmax=Sxx_max)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.colorbar()

plt.subplot(212)
plt.pcolormesh(t2, f2, Sxx2, vmin=Sxx_min, vmax=Sxx_max)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.colorbar()

基本上是从d = 1到n包含循环,并将d / d的值的d值相加。

想在Haskell中这样做,我相信需要递归。 Python等价物:

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)

2 个答案:

答案 0 :(得分:1)

你给出的例子几乎是正确的。

编写它的正确方法如下:

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

haskell中的整数除法使用div关键字完成,而正常除法则按预期使用/完成。

其次,在haskell中,您不需要使用括号作为函数参数,除非确保正确的优先级。在上面的代码中,我们需要(d-1)的括号来表示它是一个参数,而n是第二个参数。

最后,在编写纯代码时,使用保护语法通常要好得多,而不是像其他那样,如下所示:

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

如果你确实使用if else,那么分成多行通常是一个好主意,所以它更容易阅读。

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

答案 1 :(得分: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