代码之家  ›  专栏  ›  技术社区  ›  asm

sicp练习中的haskell数值类型层次

  •  5
  • asm  · 技术社区  · 14 年前

    我最近一直在学习哈斯凯尔,和一个通过SICP工作的朋友交谈。我们很想比较常见的Lisp和Scheme,所以我决定把练习1.29翻译成haskell。

    本练习使用表示数学求和函数sigma的函数sigma。这个函数接受一个函数f来应用于每个项,一个下限,一个应用于每个项以获得下一个项的函数,以及一个上限。它返回应用于每个项的f的和。

    Simpson积分应该使用Simpson规则,在范围[a,b]内用“精确”n来近似函数f的积分。我很难使这个函数工作,因为似乎有一些我不理解的东西涉及类型。

    这段代码将与6.12.1版的GHC一起编译,但是SimpsonIntegral将被赋予一个没有任何意义的类型上下文(integral a,fractional a),一旦调用它,函数就会爆炸。我曾经有过这样的工作,但我所做的显然是一个黑客,我想问一下如何用惯用的方法来处理这个问题。

    如何处理H中所需的整数-分数/实数转换?我读了很多东西,但没有任何东西看起来明显和干净。

    sigma :: (Ord a, Num b) => (a -> b) -> a -> (a -> a) -> a -> b
    sigma f a next b = iter a 0
      where
        iter current acc | current > b = acc
                         | otherwise = iter (next current) (acc + f current)
    
    simpsonIntegral f a b n = 1.0 * (h / 3) * (sigma simTerm 0 (1+) n)
      where
        h = (b - a) / n
        simTerm k = (yk k) * term
          where
            yk k = f (a + h * k)
            term =
              case k of
                0 -> 1
                1 -> 1
                otherwise -> if odd k then 4 else 2
    
    3 回复  |  直到 9 年前
        1
  •  3
  •   Travis Brown    14 年前

    跟进正义的答案:如果你想知道把 fromIntegral S,汇编如下:

    simpsonIntegral :: (Integral a, Fractional b) => (b -> b) -> a -> a -> a -> b
    simpsonIntegral f a b n = 1.0 * (h / 3) * (sigma simTerm 0 (1+) n)
      where
        h = fromIntegral (b - a) / fromIntegral n
        simTerm k = (yk k) * term
          where
            yk k = f (fromIntegral a + h * fromIntegral k)
            term = 
              case k of
                0 -> 1
                1 -> 1
                otherwise -> if odd k then 4 else 2
    

    而且似乎有效:

    *Main> simpsonIntegral (^3) 0 1 100
    0.2533333233333334
    *Main> simpsonIntegral (^3) 0 1 1000
    0.2503333333323334
    
        2
  •  6
  •   yfeldblum    14 年前
    fromIntegral :: (Integral a, Num b) => a -> b
    
    r = fromIntegral i
    
        3
  •  1
  •   Pedro Rodrigues    14 年前

    问题是函数“odd”期望它的参数是整型的。然后编译器推断变量“k”是整型的。但通过使用操作“/”,编译器推断“k”也是“fractional”类型。解决方案可以简单到将“k”转换为真正需要的整数:

    if odd (round k) then 4 else 2
    

    如果您想进一步了解Haskell中的数字转换,请检查 Converting_numbers

    作为旁注,这里是编写sigma函数的另一种方法:

    sigma f a next b = sum $ map f $ takeWhile (<= b) $ iterate next a