Haskell 哈斯克尔';用于错误检查的s if语句

Haskell 哈斯克尔';用于错误检查的s if语句,haskell,Haskell,我为Haar小波变换编写了一个函数,假设输入是一个幂为2的列表。在执行转换之前,我试图通过确保列表的长度是2的幂来进行错误检查。我正在比较列表长度的log base 2,看它是否平均(小数点右侧没有任何内容)。我认为haskell中的if语句有一些我在其他语言中不习惯的地方。如果我不进行错误检查,只需使用正确的参数调用haar,它就可以完美地工作 haar :: (Fractional a) => [a] -> [a] haar xs = if logBase 2 (fromInte

我为Haar小波变换编写了一个函数,假设输入是一个幂为2的列表。在执行转换之前,我试图通过确保列表的长度是2的幂来进行错误检查。我正在比较列表长度的log base 2,看它是否平均(小数点右侧没有任何内容)。我认为haskell中的if语句有一些我在其他语言中不习惯的地方。如果我不进行错误检查,只需使用正确的参数调用haar,它就可以完美地工作

haar :: (Fractional a) => [a] -> [a]
haar xs = if logBase 2 (fromIntegral (length xs)) /= truncate (logBase 2 (fromIntegral (length xs)))
             then error "The List must be a power of 2"
             else haarHelper xs (logBase 2 (fromIntegral (length xs)))

haarHelper xs 1 = haarAvgs xs ++ haarDiffs xs
haarHelper xs level = haarHelper (haarAvgs xs ++ haarDiffs xs) (level - 1)

haarAvgs [] = []
haarAvgs (x:y:xs) = ((x + y) / 2.0) : haarAvgs xs 

haarDiffs [] = []
haarDiffs (x:y:xs) = ((x - y) / 2.0) : haarDiffs xs
我收到以下错误消息:

functions.hs:52:13:
    Ambiguous type variable `t' in the constraints:
      `Floating t'
        arising from a use of `logBase' at functions.hs:52:13-48
      `Integral t'
        arising from a use of `truncate' at functions.hs:52:53-99
    Probable fix: add a type signature that fixes these type variable(s)
Failed, modules loaded: none.
是的,好像是用了truncate。上面显示了使用haskell编写if-then语句的更简单方法。可能对调试有点帮助

我想我可能知道。我认为truncate返回一个int,其中另一个数字是浮点

试试这个

haar :: (Fractional a) => [a] -> [a]
haar xs | r /= w = error "The List must be a power of 2"
        | otherwise = haarHelper xs (logBase 2 (fromIntegral (length xs)))
            where 
                r = logBase 2 (fromIntegral (length xs))
                w = intToFloat (truncate r) 

haarHelper xs 1 = haarAvgs xs ++ haarDiffs xs
haarHelper xs level = haarHelper (haarAvgs xs ++ haarDiffs xs) (level - 1)

haarAvgs [] = []
haarAvgs (x:y:xs) = ((x + y) / 2.0) : haarAvgs xs 

haarDiffs [] = []
haarDiffs (x:y:xs) = ((x - y) / 2.0) : haarDiffs xs

intToFloat :: Int -> Float
intToFloat n = fromInteger (toInteger n)

为了补充Matt的回答:

haar :: (Fractional a) => [a] -> [a]
haar xs | r /= (fromIntegral $ truncate r) = error "The List must be a power of 2"
        | otherwise = haarHelper xs r
            where r = logBase 2 (fromIntegral (length xs))
  • 使用
    fromIntegral
  • 您可以在
    haarHelper xs r

  • 这里有一个版本的
    haar
    ,我会说它更好一些:

    haar :: (Fractional a) => [a] -> [a]
    haar xs = maybe (error "The List must be a power of 2")
                    (haarHelper xs)
                    (intLogBase 2 $ length xs)
    
    intLogBase :: (Integral a) => a -> a -> Maybe Int
    intLogBase b n = intLogBase' b 1 n
      where
        intLogBase' b p 1 = Just p
        intLogBase' b p n
          | r /= 0    = Nothing
          | otherwise = intLogBase' b (p + 1) q 
          where (q, r) = quotRem n b
    
    intBaseLog
    baseLog
    的一种变体,适用于整数,如果给定的数字不是给定基数的幂,则返回
    Nothing
    。否则,它将返回包装在
    中的电源,只返回
    。与使用
    logBase
    truncate
    不同,它没有转换为浮点数:我们一直都有整数


    Haar中的问题有三个论点。它将计算最后一个参数,如果它是
    Nothing
    ,它将返回第一个参数(在本例中是错误)。如果最后一个参数的计算结果是
    Just
    ,它将第二个参数应用于
    Just
    中的内容并返回该值。

    这里的问题与If表达式无关。正如在其他答案中提到的,它是在您的条件下比较“logBase(…)”和“truncate(logBase(…)”。一个返回浮点类型,另一个返回整数类型。没有实现这两个类的类型(在标准库中),因此条件不能按原样很好地类型化

    我在处理二次幂时偶尔使用的一种模式是保留一个二次幂的列表,并检查该数字是否在该列表中。例如:

    powersOfTwo :: [Integer]
    powersOfTwo = iterate (*2) 1
    isPowerOfTwo x = xInt == head (dropWhile (<xInt) powersOfTwo)
        where xInt = toInteger x
    
    powersOfTwo::[Integer]
    powersOfTwo=迭代(*2)1
    
    isPowerOfTwo x=xInt==head(dropWhile(有一个更简单、更快的实现来检查正整数是否是2的幂:

    import Data.Bits
    
    powerOfTwo' n = n .&. (n-1) == 0
    
    (注意:这省略了检查
    n
    是否为正,假设我们可以依赖
    length
    中的值)

    解释,出于好奇:

    该算法依赖于一个独特的特性,即只有2的幂才有一个1位(根据定义),将其递减将反转所有较低的位:

    2^n      =  100000...
    2^n - 1  =  011111...
    
    这样就不存在公共位,使它们按位和为零

    对于所有非二次幂,减量将至少保持最高1位不变,保持按位和结果非零


    (维基百科:)

    显然,马特在我输入我的答案时编辑了他的答案。你的答案看起来更好。哈哈。但是你能解释一下美元是什么吗。对哈斯克尔本人来说还是新的。谢谢。从哈斯克尔98报告来看:$具有较低的右关联绑定优先级,因此它有时允许省略括号;例如:f$g$hx=f(g(hx))你知道这个实现对于任何长度的列表都会有非常差的性能吗?我对这个策略与logBase的速度感到好奇,所以我做了一个快速而肮脏的标准测试。对于从0到2^31随机分布的输入,这个策略的速度大约是在我的系统上使用logBase的两倍Practice它通常会更快,因为典型的列表会比它短得多,并且这种实现在较短的列表上更快。这也可以被修改以消除除法和对长度的单独调用。我想到的基本策略是实现一个
    dropExact::Int->[a]->Maybe[a]
    函数,并以连续的2次幂反复调用它(以额外的
    1
    开始)。最终操作将以
    (表示无效长度)或
    仅[]
    (表示成功,长度等于已删除的下一次2次幂)终止。
    2^n      =  100000...
    2^n - 1  =  011111...