gpt4 book ai didi

haskell - 没有 do block 或累积括号的惯用 Haskell 语法?

转载 作者:行者123 更新时间:2023-12-02 20:48:59 25 4
gpt4 key购买 nike

我对 Haskell 相当陌生,一直在尝试找到一种方法将多个 IO 污染值传递给函数来处理 C 库。大多数人似乎在 do block 中使用 <- 运算符,如下所示:

g x y = x ++ y
interactiveConcat1 = do {x <- getLine;
y <- getLine;
putStrLn (g x y);
return ()}

这让我觉得我在做 C,除了 emacs 不能自动缩进。我尝试用 Lispy 风格来写:

interactiveConcat2 = getLine >>= (\x ->
getLine >>= (\y ->
putStrLn (g x y) >>
return () ))

这看起来一团糟,并且有一串闭括号,您必须在末尾进行计数(除此之外,emacs 可以在 Lisp 中可靠地协助完成此任务,但在 Haskell 中则不行)。还有另一种说法是

import Control.Applicative
interactiveConcat3 = return g <*> getLine <*> getLine >>= putStrLn

它看起来很简洁,但不是基本语言的一部分。

是否有更省力的表示法可以将值从 IO 污点框中剥离出来?也许有一种使用 lift* 或 fmap 的更清洁的方法?我希望问什么被认为是“惯用的”不会太主观?

此外,任何使 emacs 比 (Haskell Ind) 模式更好地协作的提示将不胜感激。谢谢!

约翰

编辑:我偶然发现https://wiki.haskell.org/Do_notation_considered_harmful并意识到我编写的 lambda 链中的嵌套括号是不必要的。然而,社区(和 ghc 实现者)似乎已经接受了应用程序风格,使用 、 <*> 等,这似乎使代码更容易阅读,尽管计算运算符优先级很麻烦。

最佳答案

注意:这篇文章是用 haskell 语言写的。您可以将其另存为 Main.lhs 并在 GHCi 中尝试。

<小时/>

首先简短说明一下:您可以去掉do中的分号和大括号。 。另外,putStrLn类型为IO () ,所以你不需要return () :

interactiveConcat1 = do 
x <- getLine
y <- getLine
putStrLn $ g x y

我们将与 IO 合作,因此导入 Control.ApplicativeControl.Monad会派上用场的:

> module Main where
> import Control.Applicative

> -- Repeat your definition for completeness
> g :: [a] -> [a] -> [a]
> g = (++)

您正在寻找这样的东西:

> interactiveConcat :: IO ()
> interactiveConcat = magic g getLine getLine >>= putStrLn

magic是什么类型需要?它返回 IO String ,采用返回 String 的函数并采取平常String s,需要两个 IO String s:

magic :: (String -> String -> String) -> IO String -> IO String -> IO String

我们或许可以将这种类型概括为

> magic :: (a -> b -> c) -> IO a -> IO b -> IO c

一个quick hoogle search显示已经有两个函数几乎具有该类型: liftA2 来自Control.Applicative liftM2 来自Control.Monad 。它们是为每个 Applicative 定义的以及 – 如果是 liftM2Monad 。自 IO是两者的实例,您可以选择其中之一:

> magic = liftA2

如果您使用 GHC 7.10 或更高版本,还可以使用 <$><*>无需导入并写入 interactiveConcat作为

interactiveConcat = g <$> getLine <*> getLine >>= putStrLn

为了完整起见,我们添加 main这样我们就可以通过 runhaskell Main.lhs 轻松检查此功能:

> main :: IO ()
> main = interactiveConcat

简单的检查表明它按预期工作:

$ echo "Hello\nWorld" | runhaskell Main.lhsHelloWorld

引用文献

关于haskell - 没有 do block 或累积括号的惯用 Haskell 语法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32115828/

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