我将用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)
答案 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