gpt4 book ai didi

haskell - 惰性是否也意味着函数的值取决于调用它的上下文?

转载 作者:行者123 更新时间:2023-12-02 16:09:27 24 4
gpt4 key购买 nike

我正在尝试学习 Haskell,在使用应用仿函数时,我发现有一件事让我困惑。

让我们定义以下函数g,它返回一些仿函数:

*Main> let g = pure (2*)
*Main> :t g
g :: (Num a, Applicative f) => f (a -> a)

由于返回类型是some仿函数,因此我可以在这两个函数中使用g作为参数:

f1 :: (Num a) => [a -> a] -> a
f1 (g:[]) = g 3

f2 :: (Num a) => Maybe (a -> a) -> a
f2 (Just g) = g 4

但这意味着函数g返回的值还取决于将要评估的上下文! (可能既是 List 又是 Maybe。)这也是懒惰的特性吗?因为到目前为止,我一直在考虑惰性,即在需要时计算一个值,但在定义它时它已经确定了(对于中的g) let 表达式)。

最佳答案

正如 @augustss 所说,这与懒惰无关,而是与您正在使用类型类有关。为了使这一点更清楚,您可以通过显式传递包含类定义的所有函数的记录来建模类型类。如果您想查找更多相关信息,此技术称为“字典传递”。

我们从一些扩展开始。

{-# LANGUAGE RankNTypes      #-}
{-# LANGUAGE RecordWildCards #-}

然后给记录类型打包 Applicative 应该具有的功能(实际上,您还会有一个字段表示 f 是一个 Functor,但为了简洁起见,我在这里省略了它)。

data Applicative f =
Applicative { pure :: forall a. a -> f a
, app :: forall a b. f (a -> b) -> f a -> f b
}

我们可以将您的函数 g 定义为记录 f 是一个 Applicative 并提供您所描述的行为(我将 Num 保留为类约束,但类似地,它可以转换为记录传递)。

g :: Num a => Applicative f -> f (a -> a)
g Applicative{..} = pure (2*)

您的两个函数f1f2仍然是有效的定义:

f1 :: Num a => [a -> a] -> a
f1 (g:[]) = g 3

f2 :: Num a => Maybe (a -> a) -> a
f2 (Just g) = g 4

现在,我们想将它们应用到 g 但有一个问题:g 的函数类型需要传递 Applicative f 记录。好吧,我们可以定义 Applicative[]Maybe 实例:

applicativeList :: Applicative []
applicativeList =
Applicative { pure = (:[])
, app = \ fs as -> fs >>= \ f -> fmap f as
}

applicativeMaybe :: Applicative Maybe
applicativeMaybe =
Applicative { pure = Just
, app = \ fs as -> fs >>= \ f -> fmap f as
}

然后我们必须为应用程序选择正确的类型进行类型检查(f1[]f2 为 Maybe ):

f1g = f1 (g applicativeList)
f2g = f2 (g applicativeMaybe)

关于haskell - 惰性是否也意味着函数的值取决于调用它的上下文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31369835/

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