【问题标题】:Succinct code format when coercing data types in Haskell在 Haskell 中强制数据类型时的简洁代码格式
【发布时间】:2019-06-09 06:51:26
【问题描述】:

作为 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)来抑制警告,但代价是添加两对括号。

有没有办法在这个函数中两全其美:即简洁的代码和抑制警告?

【问题讨论】:

  • 我不熟悉那个警告,不能立即看出是什么原因造成的,但从简洁的代码来看,编写函数(imo)最惯用的方法就是@ 987654322@

标签: haskell


【解决方案1】:

这里发生的情况是您使用fromIntegralInt 转换为某种类型a,您使用sqrta 转换为a,并且您正在使用truncatea 转换回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

这些变体中的任何一个都可以简洁地解决问题。

【讨论】:

    猜你喜欢
    • 2018-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多