【问题标题】:Bind function alternative without explicitly returning to Monad绑定函数替代方案而不显式返回 Monad
【发布时间】:2017-07-09 22:33:56
【问题描述】:

我刚刚开始玩 Haskell(刚刚学习了绑定函数)。我喜欢它允许在 Monad 内从左到右链接后续操作的方式。

不知道有没有办法把下面的代码写得更好?

main = do
    print $ Just 10 
        >>= (\x -> return (x*2))
        >>= (\x -> return (x*3))

感觉 lambda 和 return 可以用某种部分应用的函数代替。我在想类似的事情:

(###) :: Maybe Int -> (Int -> Int) -> Maybe Int
(Just x) ### f = Just (f x)
Nothing ### f = Nothing

main = do
    print $ Just 10 
        >>= (\x -> return (x*2))
        >>= (\x -> return (x*3))
        ### (+3) -- the result should be (Just 63)

这当然是丑陋的、非泛型的并且不能编译:):

monads.hs:8:13:
    Couldn't match expected type `a0 -> Maybe b0'
                with actual type `Maybe Int'
    In the second argument of `(>>=)', namely
      `(\ x -> return (x * 3)) ### (+ 3)'
    In the second argument of `($)', namely
      `Just 10 >>= (\ x -> return (x * 2))
       >>= (\ x -> return (x * 3)) ### (+ 3)'
    In a stmt of a 'do' block:
      print
      $ Just 10 >>= (\ x -> return (x * 2))
        >>= (\ x -> return (x * 3)) ### (+ 3)

monads.hs:8:14:
    Couldn't match expected type `a1 -> m0 a1'
                with actual type `Maybe Int'
    The lambda expression `\ x -> return (x * 3)' has one argument,
    but its type `Maybe Int' has none
    In the first argument of `(###)', namely `(\ x -> return (x * 3))'
    In the second argument of `(>>=)', namely
      `(\ x -> return (x * 3)) ### (+ 3)'

无论如何,它似乎是一个有用的工具,能够在 monad 中链接一系列操作,而无需过多担心中间结果(无 do-notation),也无需明确指示代码何时回退到 Nothing。

  1. 是否有内置函数?
  2. 如果不是,我应该如何将我的 ### 函数更改为通用、花花公子和编译?

【问题讨论】:

  • 您的(###) 本质上是翻转fmapfmap 的类型为Functor f => (a -> b) -> f a -> f b;一旦你将它专门用于Maybe,它就会变成(a -> b) -> Maybe a -> Maybe b。另请参阅this somewhat similar question
  • 请注意,(<&>)(###) 的通用版本。

标签: haskell


【解决方案1】:

恭喜,你刚刚发明了Functors!查看sourceFunctor 实例Maybe

instance  Functor Maybe  where
    fmap _ Nothing       = Nothing
    fmap f (Just a)      = Just (f a)

m >>= return . f = fmap f m 是较少提及的单子定律之一——单子动作和函子动作之间的一种“连贯性”定律。

fmap 也有一个中缀别名(<$>),所以你可以这样写

main = print ((+3) <$> (*2) <$> (*3) <$> Just 10)

这会输出Just 63

【讨论】:

  • 谢谢。我有一种感觉,它与 Functors 有关 :) 虽然我不喜欢从右到左的处理顺序。亚历克在评论中提到的&lt;&amp;&gt; 解决了这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-14
  • 1970-01-01
  • 1970-01-01
  • 2014-03-08
相关资源
最近更新 更多