我为这些条件做了什么来跟随FP?

时间:2014-10-14 14:35:45

标签: function scala haskell functional-programming

我正在阅读FP,我有两个基本问题:

  1. FP表示函数应该接受一个输入并提供单个输出。那么我应该怎样处理void方法呢?它没有任何正确的回报?

  2. FP说功能应该是单一的 责任,然后我们如何处理方法内的log语句?这不违反规则吗?

  3. 希望知道他们如何在Scala,Haskell处理这些事情。 提前谢谢。

2 个答案:

答案 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上下文具有有意义的值,例如readFilegetLine

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活动进行日志操作。