当前位置:  开发笔记 > 编程语言 > 正文

我该如何解决这些类型的谜团?

如何解决《我该如何解决这些类型的谜团?》经验,为你挑选了1个好方法。

看到这两个问题:

--I don't want any defaulting. For example, I don't want
--a general Num to convert to Double deep within my codebase.
--I want to keep my codebase as general as possible.
--Only in main, where I actually call my pure functions,
--do I want to specify an actual, concrete type.
default ()

f :: RealFloat a => a
f = undefined

g :: Bool
g = let
        foo :: RealFloat a => a --First question: Why do I even need this?
        foo = f
    in
        foo < 2.0 --Second question: Why is this an error?

首先,为什么我需要明确地告诉Haskell类型foo?为什么它不能从类型中自动推断出来f

二,为什么不foo < 2编译?似乎很奇怪,因为foo已知是RealFloat2现在Num,这是一个祖先,RealFloat所以我认为2可以RealFloat像往常一样.

我可以通过foo :: Double代替而来解决错误foo :: RealFloat a => a.但你已经看到了我的想法default ().我不想Double在我的代码库中深入具体.我想继续RealFloat在任何地方使用,所以我可以指定我想要的准确度main.那可能是Float,Double甚至BigFloat是数字包.

简而言之,我不想在我的代码中深入指定计算精度.准确性应保持一般,并main在我要求Haskell计算事物的地方指定.

有没有摆脱这种情况的方法?



1> Roman Cheply..:

如果您将多态值(例如ffoo)视为必须在可以执行任何计算之前应用于类型参数的函数,它将有助于理解发生了什么.

(实际上,在GHC 8.0中,您将能够在语言本身中使用此类型的应用程序.)

我先回答你的第二个问题:为什么会foo < 2.0出错?因为foo是多态的,必须在某种类型实例化,以便计算结果.语义<取决于这种实例化,并且根据您选择的类型,您可能会得到不同的答案.

所以,这有效:

default ()

f :: RealFloat a => a
f = undefined

g :: Bool
g = let
        foo = f
    in
        foo < (2.0 :: Double)

应该回答你的第一个问题,"为什么我甚至需要这个?" - 你没有.

现在,看起来你真的希望你的代码具有多态性.为此,您需要g从外部了解用于计算的类型.你问:

为什么不能从f的类型中自动推断出它呢?

嗯,这是因为f它也是多态的,所以它不知道它的类型本身!它也是从类型到该类型值的函数.在程序的不同部分,它可以在不同类型实例化,并评估为不同的值.

为了告诉g使用哪种类型,您可以添加如下代理参数:

{-# LANGUAGE ScopedTypeVariables #-}

import Data.Proxy

default ()

f :: RealFloat a => a
f = undefined

g :: forall a . RealFloat a => Proxy a -> Bool
g _ = let
        foo = f
    in
        foo < (2.0 :: a)

绕过代理可能不方便.相反,您可以使用隐式参数:

{-# LANGUAGE ScopedTypeVariables, ImplicitParams #-}

import Data.Proxy

default ()

f :: RealFloat a => a
f = undefined

g :: forall a . (RealFloat a, ?t :: Proxy a) => Bool
g = let
        foo = f
    in
        foo < (2.0 :: a)

这应该可以得到你所要求的; 你可以说

let ?t = Proxy :: Proxy Double

in main,信息将g自动传播.

在GHC 8.0中,您可以Proxy通过以下方式启用来替换TypeApplications:

{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}

f :: RealFloat a => a
f = 2.0 - 1e-12

g :: forall a . RealFloat a => Bool
g = let
        foo = f @a
    in
        foo < 2

main = do
  print $ g @Float
  print $ g @Double

推荐阅读
Gbom2402851125
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有