haskell - 在 Haskell 中强制数据类型时的简洁代码格式

标签 haskell

作为 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转换 aa ,并且您正在使用 truncate转换 a返回 Int .根据对这些函数的约束,GHC 知道 a必须是 FloatingRealFrac ,但它不知道是什么a .为了解决这个问题,GHC 维护了一套默认规则;在这种情况下,他们声明任何不明确的类型是 FloatingRealFrac默认为 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/

相关文章:

haskell - cabal 错误 : Could not find module `GHC.TypeLits' . 如何修复此问题?

haskell - GHC 由于 UndecidableSuperClasses 而卡住 - 预期行为或错误?

haskell - 如何定义 Control.Functor.Constrained 的实例?

haskell - MaybeT 的 runMaybeT 参数

python - 从另一种语言调用 PyPy 沙箱

Haskell Chart 破坏堆栈构建

haskell - Text.Printf.printf 的函数组合

Haskell - 查找未声明的变量

haskell - curry (==) 是如何工作的?

haskell - 图库的 xml 树解析器 (Haskell)