Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 为stdio打印基础实验而挣扎_Haskell - Fatal编程技术网

Haskell 为stdio打印基础实验而挣扎

Haskell 为stdio打印基础实验而挣扎,haskell,Haskell,Haskell是个新手,无法在简单的程序中打印日期。我想做的是: 从getCurrentTime获取当前时间 在日期调用纯函数,返回字符串 将字符串打印到stdio 我了解到getCurrentTime返回一个IO单子。我必须用额外的酱汁,比如fmap,将我的纯函数提升到monad中。还是不走运 我做错了什么 ---编辑--- 忘了提到它编译并运行,但不生成输出 module Main where import System.IO import Data.Time.Clock import Da

Haskell是个新手,无法在简单的程序中打印日期。我想做的是:

  • 从getCurrentTime获取当前时间
  • 在日期调用纯函数,返回字符串
  • 将字符串打印到stdio
  • 我了解到getCurrentTime返回一个IO单子。我必须用额外的酱汁,比如fmap,将我的纯函数提升到monad中。还是不走运

    我做错了什么

    ---编辑---

    忘了提到它编译并运行,但不生成输出

    module Main where
    import System.IO
    import Data.Time.Clock
    import Data.Time.Calendar
    
    date :: IO (Integer,Int,Int)
    date = fmap (toGregorian . utctDay) getCurrentTime
    
    getDateStr :: (Integer,Int,Int) -> String
    getDateStr (year,month,day) = "Date is " ++ show year ++ "/" ++ show month ++ "/" ++ show day ++ "\n"
    
    main = do
        let printabledate = fmap getDateStr date
        fmap print printabledate
    
    它的工作原理如下:

    class Functor f where
        fmap :: (a -> b) -> f a -> f b
        ...
    
    • fmap::(a->b)->fa->fb
      ,注意到
      fmap
      的功能是正常功能
    • fmap getDateStr date::IO String
    • print::a->IO()
      a
      将是
      String
    所以:
    fmap打印(fmap getDateStr date)
    将具有
    IO(IO())
    类型。关键是
    print
    不是一个“正常”函数,但它是一个一元函数。如果将
    fmap
    一个一元函数转换为一元值,则会将一个一元值包装在另一个一元值中

    然后,当您计算
    main
    时,返回类型为
    IO()
    的内部一元值。那不是你想要的。要获得所需的结果,只需将
    绑定到
    可打印日期
    即可,正如@Ryan在评论中建议的那样:

        (>>=) :: m a -> (a -> m b) -> m b
        printabledate >>= print :: IO ()
    

    仅此而已。

    让我们暂时忘记单子的概念,让我们稍微澄清一下:

    在OOP中,我们有类。大多数情况下,它们会将某些行为绑定到某些数据。在Haskell中,我们不这样做,而是创建数据类型即数据

    另外,在OOP中,我们有接口的概念,它允许我们为一些类可以共享的一些常用函数定义API。在某种程度上,我们可以根据类共享的属性对这些类进行分组,例如创建一个接口
    Mappable
    ,该接口具有一个
    map
    方法,该方法将函数应用于实现该接口的类的内容

    现在,例如,我们可以创建一个类
    List
    ,该类实现
    Mappable
    ,其中
    map
    将函数应用于列表的每个元素

    在Haskell中,我们有类型类,它们类似于接口,但更好,因为它们允许您为任何现有类型实现API。例如,我们以前的
    Mappable
    ,在Haskell中被称为
    Functor
    。不要害怕,因为它只是一个类似于
    AbstractEnterpriseJavaBeanFactory
    的名称。定义如下:

    class Functor f where
        fmap :: (a -> b) -> f a -> f b
        ...
    
    现在我们可以用它扩展任何有一些内容的东西,比如我们以前的
    列表,在Haskell中是:

    data List a = ...    -- List implementation
    
    instance Functor List where
        fmap f lst = ...     -- Implementation of fmap
    
    这很好,因为
    Functor
    概念保证了函数
    f
    将应用于实现此功能的数据类型的内容,始终返回数据类型的另一个副本

    你现在可能会想,这和我的问题有什么关系

    Haskell附带了许多预定义的类型类:
    Functor
    Foldable
    Applicative

    类型类仅确保在应用API中定义的函数时满足某些约束:

    • 函子的
      fmap
      将函数
      a->b
      fa
      作为参数
    • Applicative接受一个“容器”,其中包含
      f(a->b)
      f a
    • 等等
    在所有这些类型类中,有一个具有以下API

    class X f where
        bind :: (a -> f b) -> f a -> f b
    
    这与以前的函子类似,但函数不是返回元素,而是作为参数传递,返回另一个“容器”

    此类型类称为Monad,在Haskell中定义如下:

    class Monad m where
        (>>=) :: m a -> (a -> m b) -> m b
        return :: a -> m a    -- This puts the value a inside of the "container" m
        ...
    
    (请注意,参数是翻转的)

    因此,基本上IO不是monad,只是一种容器类型,它恰好实现了type类
    monad
    中定义的API,还实现了
    Functor
    和许多其他类型(您可以在的instances部分检查它们)

    现在让我们来解释一下:

    首先,我们使用
    date
    获取
    IO(Integer,Int,Int)
    ,它基本上是一个包含三元组的容器

    然后,我们使用
    fmap
    getDateStr
    函数应用于它的内容,因此我们得到一个
    IO
    ,其中包含
    String

    现在我们将该值绑定到
    printableDate
    。因此,
    printableDate
    现在是一个
    IO字符串

    现在我们使用
    fmap
    print
    应用于
    printableDate
    的内容,但是等待,
    print
    返回一个“空”的
    IO
    容器,所以现在我们得到的是一个
    IO
    包含
    IO()
    IO(IO())
    ),但是
    main
    函数的返回类型必须始终是
    IO()

    我们现在该怎么办?我们有两个选择:

    1)使用
    =
    操作符打开
    printableDate
    中的值,期望传递给它的函数返回另一个“容器”,这就是
    print
    所做的


    使用您觉得更自然的选项,因为它们都被接受,并且

    您应该在问题中包含错误。无论如何,
    fmap print printable date
    将为您提供一个
    IO(IO())
    。您可以使用
    printabledate>>=print
    ,但更常见的是使用
    do
    printabledate
    main=print=@Ryan-Oops是的,我更新了问题来描述非结果。你的建议奏效了,尽管我还不明白为什么。想留下答案吗?
    fmap打印::
    
    main = do
        printabledate <- fmap getDateStr date
        print printabledate
    
    main = do
        let printabledate = fmap getDateStr date
        printabledate >>= print