gpt4 book ai didi

函数中的 Haskell 类型注释

转载 作者:行者123 更新时间:2023-12-03 14:24:39 25 4
gpt4 key购买 nike

Haskell 似乎无法识别下面的类型注释。为什么是这样?

这里的 Runner 是一个函数的包装器,具有 c 的默认起始值​​(“连续”)。在 rmap 中,我希望 c 有一个默认的“起始”值(例如,如果 c 是 [a],我会让该值为 [])。这里当然不方便(也许这是不好的做法,请随意提出更好的方法)是需要类型注释,因为 rmap 的域不涉及类型 c。但是,为什么我不能通过类型注释来解决这个问题?

data ExitCode = Fail | OK | Success deriving (Eq, Show)

data Runner a b c = Runner {cont ::c
, fun :: (a, c , ExitCode) ->(b, c, ExitCode)}

class Pointed a where
point :: a

rmap:: (Pointed c) => (a->b) -> Runner a b c
rmap f = Runner (point::c) (\(x,y,z) -> (f x,y,z))

错误如下。 (它似乎将 c 解释为 c1。)
Could not deduce (Pointed c1) arising from a use of `point'
from the context (Pointed c)
bound by the type signature for
rmap :: Pointed c => (a -> b) -> Runner a b c
at Runner.hs:39:8-44
Possible fix:
add (Pointed c1) to the context of
an expression type signature: c1
or the type signature for
rmap :: Pointed c => (a -> b) -> Runner a b c
In the first argument of `Runner', namely `(point :: c)'
In the expression: Runner (point :: c) (\ (x, y, z) -> (f x, y, z))
In an equation for `rmap':
rmap f = Runner (point :: c) (\ (x, y, z) -> (f x, y, z))

最佳答案

为了在这样的定义中使用类型变量,您需要 ScopedTypeVariables语言扩展,但在这种情况下,您根本不需要作用域类型变量,只需使用

rmap :: Pointed c => (a -> b) -> Runner a b c
rmap f = Runner point (\(x, y, z) -> (f x, y, z))

如果你真的很想拥有 (point :: c) , 你可以做
{-# LANGUAGE ScopedTypeVariables #-}

-- other declarations

rmap :: forall a b c. Pointed c => (a -> b) -> Runner a b c
rmap f = Runner (point :: c) (\(x, y, z) -> (f x, y, z))

ScopedTypeVariables您还必须明确使用 forall语法并具有 ab也宣布了。同样,对于这个特殊问题,GHC 可以自动找出 Pointed 的哪个实例,这不是必需的。使用。

即使使用 GHC 7.8,甚至不需要类型签名,它也可以自动派生它:
> let rmap f = Runner point (\(x, y, z) -> (f x, y, z))
> :t rmap
rmap :: Pointed c => (a -> b) -> Runner a b c

这个错误的根源是当你有 (point :: c)没有 ScopedTypeVariables , c在函数定义中是不同的 c在类型签名中。这适用于具体类型,如 Int因为它们已经在范围内,但对于类型变量却不是。

至于为什么在没有 c 的情况下可以正常工作在函数领域:GHC 的类型推断真的很聪明。它会让你传递一个通用值,直到你要求它具体化,然后所有正确的实例都被使用。例如,如果我有类似的东西
> data Test a b c = Test { t :: c, x :: (a, b) } deriving (Eq, Show)
> instance Pointed [Double] where point = [1, 2, 3] -- Requires FlexibleInstances
> let test :: Pointed c => a -> b -> Test a b c
| test a b = Test point (a, b)
> test 1 "test" :: Test Int String [Double]
Test {t = [1.0,2.0,3.0], x = (1,"test")}

即使 c不作为参数出现,当我指定返回类型为 Test Int String [Double] 时,类型检查器仍然可以确定使用哪个实例.没有指定签名,而是给了我错误
<interactive>:30:1:
No instance for (Pointed c0) arising from a use of `it'
The type variable `c0' is ambiguous
Note: there is a potential instance available:
instance Pointed [Double] -- Defined at <interactive>:19:10
In the first argument of `print', namely `it'
In a stmt of an interactive GHCi command: print it

因为它不知道 Pointed 的实例是什么使用。

关于函数中的 Haskell 类型注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25369283/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com