代码之家  ›  专栏  ›  技术社区  ›  Bartek Banachewicz

为什么这篇简单的作文不管用?

  •  7
  • Bartek Banachewicz  · 技术社区  · 6 年前

    head 在两个一元运算之间。以下是SSCCE:

    module Main where
    
    f :: IO [Int]
    f = return [1..5]
    
    g :: Int -> IO ()
    g = print
    
    main = do
        putStrLn "g <$> head <$> f"
        g <$> head <$> f
    
        putStrLn "g . head <$> f"
        g . head <$> f
    
        putStrLn "head <$> f >>= g"
        head <$> f >>= g
    

    1 . 为什么?

    f g 一起 在中间?最后我用了第三个(以 do 表示法),但我真的不喜欢它,因为它应该是一个微不足道的一行 .


    扰流警报:第三个是唯一一个打印 1 ; 另外两个人都沉默着,都在下面 runhaskell repl

    2 我确实意识到这些都是一行程序,但是操作的顺序在唯一有效的一行程序中感觉非常混乱。

    2 回复  |  直到 6 年前
        1
  •  4
  •   willeM_ Van Onsem    6 年前

    最好的写法可能是:

    f >>= g . head
    

    或者以更详细的形式:

    f >>= (g . head)
    

    所以我们基本上是执行 fmap f (因此,我们采取 head IO 蒙纳德),然后我们传给 g

    (head <$> f) >>= g
    

    在语义上是相同的。

    但是现在如果我们使用 g <$> head <$> f ? 我们先来分析一下类型:

    f :: IO [Int]
    g :: Int -> IO ()
    (<$>) :: Functor m => (a -> b) -> m a -> m b
    

    (我用过) m 在这里避免与 (功能)

    ((<$>) ((<$>) g head) f)
    

    第二个 (<$>) g :: Int -> IO () head :: [c] -> c 作为参数,这意味着 a ~ Int b ~ IO () ,和 m ~ (->) [c]

     (<$>) g head :: (->) [c] (IO ())
    

    或更详细:

    g <$> head :: [c] -> IO ()
    

    第一个 (<$>) 因此,函数将作为参数 g <$> head :: [c] -> IO () IO [Int] ,也就是说 m ~ IO a ~ [Int] , c ~ Int , ,因此我们得到类型:

    (<$>) (g <$> head) f :: IO (IO ())
    

    因此,我们不采取任何实际行动:我们 fmap公司 这个 [Int] 列表到 动作(包装在 木卫一 return (print 1) print 1 return 包裹在一个

    你当然可以“吸收”外部 木卫一 在这里,然后使用内部 ,例如:

    evalIO :: IO (IO f) -> IO f
    evalIO res = do
       f <- res
       f
    

    evalIO :: IO (IO f) -> IO f
    evalIO res = res >>= id
    

    Monad s、 但这与此无关)。

    这个 evalIO 也被称为 join :: Monad m => m (m a) -> m a

        2
  •  4
  •   Will Ness Derri Leahy    6 年前

    第一个和第二个完全一样,因为 <$> head 是函数,并且 <$> .

        g . head <$> f
    
        =  fmap (print . head) (return [1..5] :: IO [Int])
        =  do { x <- (return [1..5] :: IO [Int])
              ; return ( print (head x) ) }
        =  do { let x = [1..5] 
              ; return ( print (head x) ) } :: IO _whatever
        =       
                return ( print 1 )   :: IO (IO ())
    

    我们有太多了 return

        =  fmap (print . head) (return [1..5] :: IO [Int])
        =  return (print (head [1..5]))
        =  return (print 1)
    

    第三个是

        (head <$> f) >>= g
      = (fmap head $ return [1..5]) >>= print
      = (return (head [1..5])) >>= print
      = (return 1) >>= print