gpt4 book ai didi

haskell - 请解释一下 (forM_ [stdout, stderr] .flip hPutStrLn)::String -> IO ()

转载 作者:行者123 更新时间:2023-12-04 16:23:22 26 4
gpt4 key购买 nike

我无法理解这个 Haskell 表达式的工作原理:

import Control.Monad
import System.IO
(forM_ [stdout, stderr] . flip hPutStrLn) "hello world"

什么是 . flip hPutStrLn部分在做什么?类型签名看起来很复杂:
ghci> :type flip
flip :: (a -> b -> c) -> b -> a -> c
ghci> :type (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
ghci> :type (. flip)
(. flip) :: ((b -> a -> c1) -> c) -> (a -> b -> c1) -> c
ghci> :type (. flip hPutStrLn)
(. flip hPutStrLn) :: ((Handle -> IO ()) -> c) -> String -> c
(.) 的左右操作数是什么?运算符作为表达式被评估?

提出我的问题的另一种方法是,顶部的表达式的左侧部分如何以这样的类型签名结束:
(forM_ [stdout, stderr] . flip hPutStrLn) :: String -> IO ()

最佳答案

(.)的左右操作数是

forM_ [stdout, stderr]


flip hPutStrLn

分别。

hPutStrLn 的类型是
hPutStrLn :: Handle -> String -> IO ()

所以 flip hPutStrLn有类型
flip hPutStrLn :: String -> Handle -> IO ()

正如类型系统告诉你的那样, flip是一个交换另一个函数参数顺序的组合子。摘要中指定
flip       :: (a -> b -> c) -> b -> a -> c
flip f x y = f y x

来自 ghci你已经知道 (. flip hPutStrLn) 的类型是
ghci> :type (. flip hPutStrLn)
(. flip hPutStrLn) :: ((Handle -> IO ()) -> c) -> String -> c

从另一个方向工作,左侧的类型是
ghci> :type forM_ [stdout, stderr]
forM_ [stdout, stderr] :: Monad m => (Handle -> m b) -> m ()

观察这些类型如何组合在一起。
(. flip hPutStrLn)     ::            ((Handle -> IO ()) -> c   ) -> String -> c
forM_ [stdout, stderr] :: Monad m => (Handle -> m b ) -> m ()

结合两者(称第一个和第二个)给出
ghci> :type forM_ [stdout, stderr] . flip hPutStrLn
forM_ [stdout, stderr] . flip hPutStrLn :: String -> IO ()

在您的问题中,组合的结果应用于 String , 并产生一个产生 () 的 I/O 操作,即,我们主要对写入标准输出和错误流的副作用感兴趣。

point-free style例如您问题中的定义,程序员通过将它们与 (.) 组合起来,以更小、更简单的函数来定义更复杂的函数。 . flip组合器对于重新排序参数很有用,以便使重复的部分应用程序适合在一起。

关于haskell - 请解释一下 (forM_ [stdout, stderr] .flip hPutStrLn)::String -> IO (),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15115886/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com