【问题标题】:Haskell numeric type hierarchy in SICP exercisesSICP 练习中的 Haskell 数字类型层次结构
【发布时间】:2011-03-25 08:49:39
【问题描述】:

我最近一直在学习 Haskell,并且正在与一位正在通过 SICP 工作的朋友交谈。我们很想比较 Common Lisp 和 Scheme,所以我决定作为一个练习尝试将练习 1.29 翻译成 Haskell。

本练习使用一个函数 sigma,它表示数学求和函数 Sigma。该函数采用函数 f 应用于每个术语、一个下界、一个应用于每个术语以获得下一个术语的函数,以及一个上限。它返回应用于每个术语的 f 的总和。

simpsonIntegral 应该使用 Simpson 规则来使用“精度”n 来近似函数 f 在范围 [a, b] 上的积分。我无法使此功能正常工作,因为我似乎不了解所涉及的类型。

此代码将使用 ghc 版本 6.12.1 进行编译,但 simpsonIntegral 将获得一个没有任何意义的类型上下文(Integral a, Fractional a),并且该函数在您调用它时立即崩溃。我曾经做过这个工作,但我所做的显然是一种黑客行为,我想在这里问一下如何以惯用方式处理它。

如何习惯性地处理 h 中所需的 Integral -> Fractional/Real 转换?我读了很多东西,但似乎没有什么明显和干净的。

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

【问题讨论】:

    标签: haskell types type-conversion


    【解决方案1】:
    fromIntegral :: (Integral a, Num b) => a -> b
    
    r = fromIntegral i
    

    【讨论】:

    • 关于fromIntegral的问题。我正在尝试这个,但不是按照 Travis 的回答在正确的位置,我认为它不起作用,因为根据这个 haskell.org/tutorial/numbers.html num 不提供除法运算符。 fromIntegral 返回类型是否具有多态性,而 ghc 推断我想要一个 Fractional 返回类型?
    • 是的,fromIntegral 在其返回类型b 中是多态的,因为b(返回类型)允许是任何属于Num 类型成员的数据类型班级。虽然Num 类型类不提供除法,但属于该类型类成员的某些数据类型确实提供了除法,例如Double
    【解决方案2】:

    跟进Justice的回答:如果您对fromIntegrals 的放置位置感到好奇,请编译以下内容:

    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
    

    【讨论】:

      【解决方案3】:

      问题是函数“odd”期望它的参数是一个 Integral 类型。然后编译器推断您的变量“k”是 Integral 类型。但是通过使用“/”操作,编译器推断“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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-28
        • 2012-07-05
        • 2011-11-05
        • 2017-02-03
        • 2010-12-26
        • 2012-12-15
        • 2021-05-23
        • 1970-01-01
        相关资源
        最近更新 更多