【问题标题】:Combining (a -> Maybe a) and (a -> a) functions结合 (a -> Maybe a) 和 (a -> a) 函数
【发布时间】:2016-03-31 17:41:33
【问题描述】:

我有两个功能:

f :: a -> Maybe a
g :: a -> a

我想创建这样的功能:

h :: a -> Maybe a

h x
| isJust(f x) = Just (g $ fromJust(f x))
| otherwise   = Nothing

我怎样才能以更优雅的方式做到这一点?

【问题讨论】:

  • 优雅的方式贴在下面。不过,我想提醒一下,使用isJust/fromJust 可以说是最不优雅的方式。事实上,如果忘记了isJust 检查,fromJust 可能会使您的程序崩溃。更好的方法是使用模式匹配,例如case f x of Nothing -> Nothing ; Just y -> Just $ g y。另请参阅boolean blindness 了解更多信息。
  • 类型不正确。 g (fromJust (f x)) : a。我想你提醒Just (g (fromJust (f x))

标签: function haskell functional-programming dot-operator


【解决方案1】:

拥有

fmap2 :: (Functor g, Functor f) => (a -> b) -> g (f a) -> g (f b)
fmap2 = fmap . fmap

这是一个有趣的方式:

h :: a -> Maybe a
h = fmap2 g f

fmap2 g f ~> fmap (fmap g) f ~> fmap g . f ~> \x -> fmap g (f x)

这里使用Functor ((->) r) 实例:fmap 可以用来代替(.)

【讨论】:

  • 鉴于用户(可能)是 Haskell 的新手,您会添加一些解释吗?不是每个人都熟悉Functor ((->) r)。使用b ~ af a ~ Maybe ag c ~ a -> c 会让他们更清楚这一点。
  • @Zeta,我想让它看起来像一个谜题。
  • 所以,在fmap . fmap 中,左边的fmap(a ->) 中,因为fmap g 始终是一个函数,无论函子是什么。右边的fmap 恰好在Maybe 中。 (在 owl 组合器中,它也在 (r ->) 中。很好。)
【解决方案2】:

为什么不简单地这样做:

h :: a -> Maybe a
h x = fmap g (f x)

或运营商版本:

h :: a -> Maybe a
h x = g <$> f x

【讨论】:

    【解决方案3】:

    由于您已使用 标记此问题:

    h :: a -> Maybe a
    h = fmap g . f
    

    解释:

    f            ::                          a -> Maybe a
    g            ::        a ->       a
    fmap g       ::  Maybe a -> Maybe a
    (.)          :: (Maybe a -> Maybe a) -> (a -> Maybe a) -> (a -> Maybe a)
    (.) (fmap g) ::                         (a -> Maybe a) -> (a -> Maybe a)
    fmap g . f   ::                                           (a -> Maybe a)
    h            ::                                            a -> Maybe a
    

    请注意,(.)fmap g 的类型实际上更通用:

    (.) :: (b -> c) -> (a -> b) -> (a -> c)
    -- b in this case is Maybe a
    -- c in this case is Maybe a
    
    fmap g :: Functor f => f a -> f a
    -- f in this case is Maybe
    

    但是,您也可以对 f 的结果进行模式匹配:

    h x = 
      case f x of
        Just k -> Just (g k)
        _      -> Nothing
    

    请注意,您的原始示例甚至无法编译,因为 g 的返回类型不正确。

    【讨论】:

    • 我认为这是最惯用的方式,也是所有选项中表达思想最清晰的方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 2017-11-21
    相关资源
    最近更新 更多