在`floor中输入默认值。 sqrt`

时间:2018-09-27 12:40:02

标签: haskell

使用-Wtype-defaults(随-Wall附带),floor . sqrt . fromIntegral会给我一系列警告,即使我指定了参数的类型和结果也是如此:

λ> (floor . sqrt . fromIntegral) (10 :: Int) :: Int

<interactive>:356:2-6: warning: [-Wtype-defaults]
    • Defaulting the following constraints to type ‘Double’
        (RealFrac a0)
          arising from a use of ‘floor’ at <interactive>:356:2-6
        (Floating a0)
          arising from a use of ‘sqrt’ at <interactive>:356:10-13
        (Num a0)
          arising from a use of ‘fromIntegral’ at <interactive>:356:17-28
    • In the first argument of ‘(.)’, namely ‘floor’
      In the expression: floor . sqrt . fromIntegral
      In the expression: (floor . sqrt . fromIntegral) (10 :: Int) :: Int

<interactive>:356:2-6: warning: [-Wtype-defaults]
    • Defaulting the following constraints to type ‘Double’
        (RealFrac a0)
          arising from a use of ‘floor’ at <interactive>:356:2-6
        (Floating a0)
          arising from a use of ‘sqrt’ at <interactive>:356:10-13
        (Num a0)
          arising from a use of ‘fromIntegral’ at <interactive>:356:17-28
    • In the first argument of ‘(.)’, namely ‘floor’
      In the expression: floor . sqrt . fromIntegral
      In the expression: (floor . sqrt . fromIntegral) (10 :: Int) :: Int
3

我可以通过为fromIntegral指定非多态类型来解决此问题:

λ> (floor . sqrt . (fromIntegral :: Int -> Double)) (10 :: Int) :: Int
3

以下内容也可以使用,但更麻烦:

λ> (floor . sqrt . (fromIntegral :: (Integral a) => a -> Double)) (10 :: Int) :: Int
3

我的问题是:

  • 是否有更简单的方法来处理类型默认警告? (关闭-Wtype-defaults不符合条件。)
  • 这是在Haskell中计算此复合函数(平方根底数)的值的正确方法吗?不得不使用fromIntegral并必须指定中间类型使我想起了谚语“简单的事情很难。”

2 个答案:

答案 0 :(得分:4)

共有三种类型可供选择(输入类型,内部使用的中间浮点类型以及结果类型),您必须以某种方式将所有这三种情况告诉编译器。每种修复方法都有很多组合,但是不能少于三个。

我认为TypeApplications是指定这些类型的一种特别方便的方法。这是从原始文件开始的一种方法,该文件有两个注释,并且仅添加一个注释可以避免默认设置:

> :set -XTypeApplications -Wtype-defaults
> (floor . sqrt @Double . fromIntegral) (10 :: Int) :: Int
3

这是另一个可能更符合人体工程学的方法(因为它对于括号的确切位置更加灵活):

> (floor . sqrt . fromIntegral @Int @Double) 10 :: Int
3

我喜欢您的第三个示例的想法,该示例是修改第二个示例,以使您不必重复Int,从而避免了潜在的脆弱性。通过使用特殊的_类型应用程序,您可以使用类型应用程序以稍微麻烦的方式实现此目的,该方法使编译器对类型变量之一使用常规的推断过程:

> (floor . sqrt . fromIntegral @_ @Double) (10 :: Int) :: Int
3

答案 1 :(得分:4)

  

这是在Haskell中计算此复合函数(平方根底数)的值的正确方法吗?不得不使用fromIntegral并必须指定中间类型使我想起了谚语“简单的事情很难。”

您最终将要计算整数平方根,因此,理想情况下,您希望避免通过sqrt :: Floating a => a -> a进行计算。你可能会的。例如,使用 arithmoi 库中的integerSquareRoot :: Integral a => a -> a

关于您的第一个问题,我第二次Daniel Wagner's suggestion使用TypeApplications扩展名来指定中间类型。