(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)就不是一回事了
当然,这可以用多种方式来写:上面的天真版本,使用 Maybe
是 Monad
的事实,使用 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
就是这种情况。现在,弄清楚剩下的:)
给定一个函数:(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)就不是一回事了
当然,这可以用多种方式来写:上面的天真版本,使用 Maybe
是 Monad
的事实,使用 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
就是这种情况。现在,弄清楚剩下的:)