(Haskell) 将函数类型转换为 maybe

(Haskell) Converting a functions type into maybe

给定一个函数:(a -> a) 我们应该获取函数并将其类型转换为 (Maybe a -> Maybe a)。我有点坐在这里尝试一切可能,但我只得到了 Maybe (a -> a) 类型,但我没有改变实际输入和输出的想法。那么有人可以给我一些解决这个问题的提示或想法,这样我就可以自己尝试了吗?谢谢

假设你有

f :: a -> a

并且你需要构建

g :: Maybe a -> Maybe a
g = ...

我们如何构建它?首先,它是一个参数的函数,所以它应该是这样的:

g = \x -> ...

其次,我们有一个Maybe类型的参数,所以我们可以分别分析两种情况:

g = \x -> case x of
  Nothing -> ... (1)
  Just y -> ... (2)

在(1)中,我们不能做太多:我们不能产生抽象类型的值a,所以不能使用Just。我们唯一可以使用的是 Nothing.

在(2)中,我们有三种选择:

a) Nothing 再次,所以我们得到一个无聊的解决方案:

g = \x -> case x of
  Nothing -> Nothing
  Just y -> Nothing

这就是

g = \x -> Nothing

b) 或者,我们有一个 y::a,所以我们可以 return Just y:

g = \x -> case x of
  Nothing -> Nothing
  Just y -> Just y

这就是

g = \x -> x -- = id

c) 或者,我们可以将 f 应用于 y,以获得类型为 a 的新值。然后我们需要做的就是将这个值包装在 Just:

g = \x -> case x of
  Nothing -> Nothing
  Just y -> Just (f y)

正如@chi 指出的那样,我们可以继续对结果应用 f,因此我们也可以对任意数量的 f 应用 return Just (f (f ... (f y)...))

只有 (c) 使用过 f,因此它是这里唯一的重要解决方案。

为了完整起见,值得注意的是对于现实世界的应用,(b) 和 (c) 是等价的,因为 f 除了 id.

正如@amalloy 所指出的,如果我们将 f 作为参数而不是全局函数,则情况并非如此,因为只有 id 可以作为任何 a->a a,但是对于给定的 a,有许多类型为 a->a 的函数。所以如果你的 g 应该是

g :: (a->a)->(Maybe a->Maybe a)

那么(b)和(c)就不是一回事了

当然,这可以用多种方式来写:上面的天真版本,使用 MaybeMonad 的事实,使用 Functor Maybe 中的 fmap (感谢@amalloy),但结果是一样的。

真的很难避免这个问题的最终答案,因为这是一个微不足道的问题,真的。

检查标准函数的签名fmap(我将删除约束部分,因为我们现在不需要它):

fmap :: (a -> b) -> f a -> f b

您可以将其视为两个参数 (a -> b)f a 的函数,生成结果 f b。但是下面的签名是完全一样的:

fmap :: (a -> b) -> (f a -> f b)

钟声响起了吗?是的,fmap 也可以看作是一个参数 (a -> b) 的函数,结果产生 (f a -> f b) 函数。

现在,这些签名中的 f 表示具有 Functor 实例的任何类型,其中 Maybe 就是这种情况。现在,弄清楚剩下的:)