我对Haskell相当陌生,并且一直在试图找到一种方法将多个io污染的值传递给函数以处理C库。大多数人似乎在do块中使用<-操作符,如下所示:
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污染盒中剥离值?也许有一个更干净的方式使用升降机*或fmap?我希望问什么是"习惯用语"不会太主观。
此外,任何使emacs比(Haskell Ind)模式更好地协作的技巧都将非常感谢。谢谢!
约翰编辑:我偶然发现https://wiki.haskell.org/Do_notation_considered_harmful并意识到我写的lambda链中的嵌套括号是不必要的。然而,社区(和ghc实现者)似乎已经接受了应用程序启发的风格,使用<*>等,这似乎使代码更容易阅读,尽管计算操作符优先级令人头痛。
注意:这篇文章是用读写Haskell写的。您可以将其保存为Main。请在您的GHCi中尝试。
先说一句:你可以去掉do
中的分号和大括号。此外,putStrLn
具有类型IO ()
,因此您不需要return ()
:
interactiveConcat1 = do
x <- getLine
y <- getLine
putStrLn $ g x y
我们将使用IO
,因此导入Control.Applicative
或Control.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
一个快速的hoogle搜索显示,已经有两个函数几乎是这种类型:Control.Applicative
中的liftA2
和Control.Monad
中的liftM2
。它们被定义为每个Applicative
和liftM2
- Monad
。由于IO
是两者的实例,您可以选择其中之一:
> magic = liftA2
如果您使用GHC 7.10或更高版本,您也可以使用<$>
和<*>
而不需要导入,并将interactiveConcat
写入
interactiveConcat = g <$> getLine <*> getLine >>= putStrLn
为了完整起见,让我们添加一个main
,以便我们可以通过runhaskell Main.lhs
轻松检查此功能:
> main :: IO ()
> main = interactiveConcat
一个简单的检查显示它按预期工作:
$ echo "HellonWorld" | runhaskell Main.lhsHelloWorld 之前引用
-
Applicative
在分类目录 - LYAH的"For a Few Monads More"一章中的"一些有用的单元函数"一节。
您可以使用liftA2
(或Control.Monad
中的liftM2
):
import Control.Applicative (liftA2)
liftA2 g getLine getLine >>= putStrLn