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 给出警告 Defaulting the following constraint to type `Double'。我可以通过将结果从 sqrt 强制为 Double 来抑制警告(请参阅 intSqrt2),但代价是添加两对括号。
有没有办法在这个功能中两全其美:即简洁的代码和抑制警告?
解决方案
这里发生的情况是,您fromIntegral
用于将 an 转换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
这些变体中的任何一个都可以简洁地解决问题。
推荐阅读
- angular - Angular 7+ 中的共享动画
- c# - 如何在军刀汽车价格空气交换肥皂 api 请求中发送段号
- python - 在每次迭代时在带有标识列的 pandas 上迭代地创建一个数据框
- flutter - Flutter App 介绍与用户交互
- javascript - Fancybox 导致我的另一个
你好,我想知道如何将我的fancybox 仅应用于一个标签而不是我的所有标签,因为它们会搞砸。有没有办法停止代码,所以它不会弄乱页面上的其余 a 标签。或者也许将fancybox设置为仅对一个标签ID起作用。
这是我在页面上的 fancybox 脚本:
$(document).ready(function()
- selenium - 当我们使用 jenkins 执行构建时,testng-failed.xml 没有创建
- q# - Q#中为什么用返回类型Unit来描述没有返回值的操作;相对于无效或无?
- jquery - 为什么我看到 webpack 模块 7 不是一个函数?
- r - 根据最长行重塑r中的数据框
- java - 连接未释放回 tomcat jdbc 池