作为 Haskell 的初学者,我试图在 ghc 编译器中使用 -Wall 选项时,在没有警告的情况下编译所有练习代码。我也想了解 '$' 和 '.' 的用法。避免括号过多。
在下面的代码中
module Helpers (intSqrt1, intSqrt2) where
intSqrt1 :: Int -> Int
intSqrt1 x = truncate $ sqrt $ fromIntegral x
intSqrt2 :: Int -> Int
intSqrt2 x = truncate ( sqrt (fromIntegral x) :: Double)
intSqrt1 给出警告默认以下约束键入“Double”。我可以通过将结果从 sqrt 强制转换为 Double(参见 intSqrt2)来抑制警告,但代价是添加两对括号。
有没有办法在这个功能中两全其美:即简洁的代码和抑制警告?
最佳答案
这里发生的事情是您正在使用 fromIntegral
转换 Int
到某种类型 a
,您正在使用 sqrt
转换 a
至 a
,并且您正在使用 truncate
转换 a
返回 Int
.根据对这些函数的约束,GHC 知道 a
必须是 Floating
和 RealFrac
,但它不知道是什么a
是 .为了解决这个问题,GHC 维护了一套默认规则;在这种情况下,他们声明任何不明确的类型是 Floating
或 RealFrac
默认为 Double
.但是,在所有情况下,默认行为可能不是预期的行为,因此 GHC 也会打印警告。
当您添加类型签名时,歧义被消除,这就是消息消失的原因。不过,添加类型签名有点笨拙;有没有更好的办法?其实,有!首先,您需要启用 TypeApplications
通过将以下编译指示放在文件顶部来扩展:
{-# LANGUAGE TypeApplications #-}
此扩展使您可以使用语法
@SomeType
作为任何函数的第一个参数;如果函数在其签名中有任何类型变量,则将第一个特化为 SomeType
. (后续使用专门用于第二、第三、第四等类型变量。)在这种情况下,我们可以选择放置类型应用程序的位置。我们可以戴上 fromIntegral
:intSqrt x = truncate $ sqrt $ fromIntegral @_ @Double x
(注意
fromIntegral
有两个类型变量,所以我们将第一个变量推断为 Int
并且只特化第二个。)或者我们可以把它放在
sqrt
:intSqrt x = truncate $ sqrt @Double $ fromIntegral x
或在
truncate
:intSqrt x = truncate @Double $ sqrt $ fromIntegral x
这些变体中的任何一个都可以简洁地解决问题。
关于haskell - 在 Haskell 中强制数据类型时的简洁代码格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56510549/