我是Haskell的新手,并且一直试图找到一种方法将多个IO污染的值传递给一个处理C库的函数.大多数人似乎在do块中使用< - 运算符,如下所示:
g x y = x ++ y
interactiveConcat1 = do {x <- getLine;
y <- getLine;
putStrLn (g x y);
return ()}
Run Code Online (Sandbox Code Playgroud)
This makes me feel like I'm doing C, except emacs can't auto-indent. I tried to write this in a more Lispy style:
interactiveConcat2 = getLine >>= (\x ->
getLine >>= (\y ->
putStrLn (g x y) >>
return () ))
Run Code Online (Sandbox Code Playgroud)
That looks like a mess, and has a string of closed parentheses you have to count at the end (except again, emacs can reliably assist with this task in Lisp, but not in Haskell). Yet another way is to say
import Control.Applicative
interactiveConcat3 = return g <*> getLine <*> getLine >>= putStrLn
Run Code Online (Sandbox Code Playgroud)
which looks pretty neat but isn't part of the base language.
Is there any less laborious notation for peeling values out of the IO taint boxes? Perhaps there is a cleaner way using a lift*or fmap? I hope it isn't too subjective to ask what is considered "idiomatic"?
Also, any tips for making emacs cooperate better than (Haskell Ind) mode would be greatly appreciated. Thanks!
John
编辑:我偶然发现了https://wiki.haskell.org/Do_notation_considered_harmful,并意识到我写的lambda链中的嵌套括号不是必需的.然而,似乎社区(和ghc实现者)已经使用了<*>等接受了Applicative风格的样式,这似乎使代码更容易阅读,尽管头痛并计算出运算符优先级.
Zet*_*eta 15
注意:这篇文章是用文字Haskell编写的.您可以将其保存为Main.lhs并在GHCi中尝试.
首先简短说一句:你可以摆脱分号和括号do.此外,putStrLn有类型IO (),所以你不需要return ():
interactiveConcat1 = do
x <- getLine
y <- getLine
putStrLn $ g x y
Run Code Online (Sandbox Code Playgroud)
我们将合作IO,所以进口Control.Applicative或Control.Monad将派上用场:
> module Main where
> import Control.Applicative
> -- Repeat your definition for completeness
> g :: [a] -> [a] -> [a]
> g = (++)
Run Code Online (Sandbox Code Playgroud)
你正在寻找这样的东西:
> interactiveConcat :: IO ()
> interactiveConcat = magic g getLine getLine >>= putStrLn
Run Code Online (Sandbox Code Playgroud)
magic需要什么类型?它返回一个IO String,取一个函数返回一个String并采用通常的Strings,并取两个IO Strings:
magic :: (String -> String -> String) -> IO String -> IO String -> IO String
Run Code Online (Sandbox Code Playgroud)
我们可以将这种类型概括为
> magic :: (a -> b -> c) -> IO a -> IO b -> IO c
Run Code Online (Sandbox Code Playgroud)
一个快速的搜索显示,已经有两种功能几乎就是这种类型:liftA2来自Control.Applicative和liftM2来自Control.Monad.它们是为每一个Applicative而定义的- 如果是liftM2- Monad.既然IO是两者的实例,您可以选择其中一个:
> magic = liftA2
Run Code Online (Sandbox Code Playgroud)
如果你使用GHC 7.10或更高版本,你也可以使用<$>和<*>无进出口写interactiveConcat为
interactiveConcat = g <$> getLine <*> getLine >>= putStrLn
Run Code Online (Sandbox Code Playgroud)
为了完整性,我们添加一个,main以便我们可以通过runhaskell Main.lhs以下方式轻松检查此功能:
> main :: IO ()
> main = interactiveConcat
Run Code Online (Sandbox Code Playgroud)
一个简单的检查表明它按预期工作:
$ echo "Hello\nWorld" | runhaskell Main.lhs HelloWorld
Applicative 在Typeclassopedia中| 归档时间: |
|
| 查看次数: |
217 次 |
| 最近记录: |