我正在阅读FP,我有两个基本问题:
FP表示函数应该接受一个输入并提供单个输出。那么我应该怎样处理void
方法呢?它没有任何正确的回报?
FP说功能应该是单一的
责任,然后我们如何处理方法内的log
语句?这不违反规则吗?
希望知道他们如何在Scala,Haskell处理这些事情。 提前谢谢。
答案 0 :(得分:9)
我假设您正在阅读一本名为“#34; Functional Programming"”的书,尽管它有助于了解作者是谁。在任何情况下,这些问题都相对容易回答,我会就Haskell给出答案,因为我不了解Scala。
那么我该如何处理void方法呢?它没有任何回报吗?
像Haskell这样的纯函数语言中没有void
个方法。纯函数没有副作用,所以没有返回值的纯函数是没有意义的,比如
f :: Int -> ()
f x = let y = x * x + 3 in ()
不进行任何计算,永远不会计算y
,并且您提供的所有输入都将返回相同的值。但是,如果您有一个不纯的函数,例如写入文件或在屏幕上打印某些内容的函数,那么它必须存在于 monadic context 中。如果您还不了解monad,请不要担心。他们需要一点时间来适应,但它们是一个非常强大和有用的抽象,可以使很多问题更容易。 monad类似于IO
,在Haskell中,它接受一个类型参数来指示可以存储在此上下文中的值。所以你可以拥有像
putStrLn :: String -> IO ()
或者
-- FYI: FilePath is an alias for String
writeFile :: FilePath -> String -> IO ()
这些具有副作用,由IO something
的返回值表示,而()
表示该操作没有有意义的结果。例如,在Python 3中,print
函数返回None
,因为在将值打印到屏幕后没有任何有意义的返回值。 ()
也可以表示monadic上下文具有有意义的值,例如readFile
或getLine
:
getLine :: IO String
readFile :: FilePath -> IO String
在编写main
函数时,您可以执行类似
main = do
putStrLn "Enter a filename:"
fname <- getLine -- fname has type String
writeFile fname "This text will be in a file"
contents <- readFile fname
putStrLn "I wrote the following text to the file:"
putStrLn contents
FP说功能应该具有单一的责任,那么我们如何处理方法中的日志语句?那不违反规则吗?
大多数功能都不需要在其中登录。我知道这听起来很奇怪,但这是真的。在Haskell和大多数其他函数式语言中,您将编写许多小的,易于测试的函数,每个函数都执行一步。在您的应用程序中有很多1或2行函数是很常见的。
当您确实需要进行日志记录时,请说您正在构建Web服务器,您可以采用几种不同的方法。实际上有一个名为Writer
的monad允许您在执行操作时聚合值。这些操作不必是不纯的,做IO,它们可以完全是纯粹的。但是,可能用于Web服务器或大型应用程序的真正日志记录框架可能会带有自己的框架。这样您就可以设置日志记录到屏幕,文件,网络位置,电子邮件等。这个monad将包装IO
monad,以便它可以执行这些副作用。更高级的可能会使用一些更高级的库,如monad变换器或可扩展的效果。这些让你&#34;结合&#34;不同的monad在一起,所以你可以同时使用实用程序。你可能会看到像
type MyApp a = LogT IO a
-- log :: Monad m => LogLevel -> String -> LogT m ()
getConnection :: Socket -> MyApp Connection
getConnection sock = do
log DEBUG "Waiting for next connection"
conn <- liftIO $ acceptConnection sock
log INFO $ "Accepted connection from IP: " ++ show (connectionIP conn)
return conn
我不希望您完全理解此代码,但我希望您可以看到它将日志记录和网络操作混合在一起。 liftIO
函数是一个常见的函数,monad变换器&#34;转换&#34; IO操作进入包含IO的新monad。
这可能听起来很混乱,如果你习惯使用Python,Java或C ++这样的语言,那么它起初可能就是这样。我当然是!但是在我习惯以不同的方式思考问题之后,我希望我一直都有这些OOP语言的结构。
答案 1 :(得分:3)
我可以从Haskell的角度回答。
FP表示函数应该接受一个输入并提供单个输出。那么我该如何处理void方法呢?它没有任何回报吗?
因为这实际上是什么功能!在数学中,每个函数都需要一些输入并给你一些输出。如果不给出任何输入,你不能指望一些输出。您在其他语言中看到的void
方法在数学方面没有意义。但实际上其他语言中的void
方法会执行某种IO操作,在Haskell中将其抽象为IO
monad。
我们如何处理方法中的日志语句
您可以使用monad变换器堆栈并提升IO
日志操作以执行此操作。实际上,编写器monad可以完全没有任何IO
活动进行日志操作。