可能懒惰也意味着函数的值取决于它被称为的上下文?

时间:2015-07-12 16:11:40

标签: haskell applicative

我正在努力学习Haskell,在玩弄应用函子时,我发现有一件事困扰着我。

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

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

由于返回类型是某些仿函数,我可以在这两个函数中使用 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 中让表达)。

1 个答案:

答案 0 :(得分:7)

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

我们从一些扩展开始。

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

然后给记录类型打包Applicative应该具有的功能(实际上你还有一个字段说fFunctor但是我为简洁起见,请在此省略。

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

我们可以将您的函数g定义为记录fApplicative并传达您所描述的行为(我将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条记录。好吧,我们可以定义[]的{​​{1}}和Maybe个实例:

Applicative

然后我们必须选择正确的应用程序来进行类型检查(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 Maybe):

f2