Haskell函数:获取日期的一部分作为字符串

6

我有一个初学者的问题,关于Haskell中的日期和String

我需要以String的形式获取日期的一部分(年、月或日)。我发现,如果我在GHCi中写下以下两行:

Prelude> now <- getCurrentTime
Prelude> let mon = formatTime defaultTimeLocale "%B" now

那么mon的类型为String。然而,我无法将其放入函数中。例如,我尝试了以下内容:

getCurrMonth = do
    now <- getCurrentTime
    putStrLn (formatTime defaultTimeLocale "%B" now)

但是这个返回类型是 IO (),而我需要的是 String (也不是 IO String,只是 String)。

我知道 do 语句创建了一个单子,但我找不到任何其他方法来在 Haskell 中获取日期。

那么,有没有办法编写这样的函数呢?

非常感谢您提供的任何帮助!

4个回答

10

如果你想返回表示当前时间的字符串,它必须在IO monad中,因为当前时间的值总是在变化!

你可以在IO monad中返回一个字符串:

> getCurrMonth :: IO String
> getCurrMonth = do
>    now <- getCurrentTime
>    return (formatTime defaultTimeLocale "%B" now)

然后,从您的顶层(例如在主函数中),您可以传递该字符串:

> main = do
>     s <- getCurrMonth
>     ... do something with s ...

5

如果你真的想要这样的纯函数,那么你需要将时间显式地作为参数传入。

import System.Locale (defaultTimeLocale)
import System.Time (formatCalendarTime, toUTCTime, getClockTime, ClockTime)

main = do now <- getClockTime
          putStrLn $ getMonthString now

getMonthString :: ClockTime -> String
getMonthString = formatCalendarTime defaultTimeLocale "%B" . toUTCTime

请注意,getMonthString可以是纯函数,因为IO操作getClockTime在其他地方执行。
我使用了old-time函数,因为我在codepad上测试它,显然没有新的time包。 :( 我对旧时间函数不熟悉,所以可能会差几个小时,因为它使用toUTCTime

2
展示如何尽可能地减少“不纯部分”的方法,加1。 - Landei

2
正如Don所说,在这种情况下,无法避免使用monads。请记住,Haskell是一种纯函数式语言,因此给定特定输入,函数必须始终返回相同的输出。Haskell.org提供了一个很好的解释和介绍在这里,肯定值得一看。您还可以从像这样的monad介绍或像这样的Haskell I/O教程中受益。当然,您可以在网上找到更多资源。Monads最初可能令人生畏,但它们实际上并不像一开始看起来那么困难。
哦,我强烈建议不要使用unsafePerformIO。它有“unsafe”这个词是有很好的理由的,它绝对不是为这种情况而创建的。使用它只会导致不良习惯和日后的问题。
祝您学习Haskell顺利!

非常感谢您提供的链接,我终于能够更好地理解单子了。我们在学校学习 Haskell 的方式非常令人困惑。 - robodasha

1

你不能只得到一个字符串,它必须是IO字符串。这是因为getCurrMonth不是一个纯函数,在不同的时间返回不同的值,所以它必须在IO中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接