Haskell 括号()本身是什么意思?

Haskell 括号()本身是什么意思?,haskell,parentheses,Haskell,Parentheses,我读了那本书 枚举成员是按顺序排列的类型此类中的类型: (),Bool,Char 它也出现在一些签名中: putChar :: Char -> IO () 在谷歌上很难找到关于它的信息,因为答案涉及到“公共括号”(用于函数调用、优先级问题等)的问题 因此,表达式()是什么意思?它是一种类型吗?什么是()类型的变量?用于什么以及何时需要它?它既是类型又是值()是一种特殊类型的“发音”单位,它有一个值:(),也是发音单位。它本质上与Java或C/C++中的类型void相同。如果您熟悉

我读了那本书

枚举成员是按顺序排列的类型此类中的类型: (),Bool,Char

它也出现在一些签名中:

putChar  ::    Char -> IO ()
在谷歌上很难找到关于它的信息,因为答案涉及到“公共括号”(用于函数调用、优先级问题等)的问题


因此,表达式
()
是什么意思?它是一种类型吗?什么是
()
类型的变量?用于什么以及何时需要它?

它既是类型又是值
()
是一种特殊类型的“发音”单位,它有一个值:
()
,也是发音单位。它本质上与Java或C/C++中的类型
void
相同。如果您熟悉Python,可以将其视为具有singleton
None
NoneType

当您想要表示不返回任何内容的操作时,它非常有用。它最常用于monad的上下文中,例如
IO
monad。例如,如果您具有以下功能:

getVal :: IO Int
getVal = do
    putStrLn "Enter an integer value:"
    n <- getLine
    return $ read n
然后

但是,您不必自己编写此函数,它已经存在于
控件中。Monad
作为函数
void
,它的约束性更小,可以在
Functor
上工作:

void :: Functor f => f a -> f ()
void fa = fmap (const ()) fa
为什么它在
Functor
上工作而不是在
Monad
上工作?对于每个
Monad
实例,您可以将
Functor
实例编写为

instance Monad m => Functor m where
    fmap f m = m >>= return . f

但是你不能用每个
函子
生成
单子。这就像一个正方形是一个矩形,但一个矩形并不总是一个正方形,单子是函子的子集。

它既是一个类型也是一个值


它是,只有一个值的类型。在Haskell中,它的名称和唯一的值看起来像空元组:
()

,正如其他人所说,它是一种单位类型,它有一个称为单位的值。在Haskell语法中,这很容易表示为
()::()
。我们也可以很容易地做自己的

data Unit = Unit

>>> :t Unit :: Unit
Unit :: Unit
>>> :t () :: ()
() :: ()
它被写成
()
,因为它的行为非常像一个“空元组”。这有理论上的原因,但老实说,它也有很多简单的直觉意义

它通常用作类型构造函数的参数,如
IO
ST
,当它是感兴趣的值的上下文而不是值本身时。这在直觉上是正确的,因为如果我告诉你我有一个
()
类型的值,那么你不需要知道更多的东西——它们只有一个

putStrLn :: String -> IO ()     -- the return type is unimportant,
                                -- we just want the *effect*

map (const ()) :: [a] -> [()]   -- this destroys all information about a list
                                -- keeping only the *length*

>>> [ (), (), () ] :: [()]      -- this might as well just be the number `3`
                                -- there is nothing else interesting about it

forward :: [()] -> Int          -- we have a pair of isomorphisms even
forward = length

backward :: Int -> [()]
backward n = replicate n ()

正如其他人所说,Haskell中的
()
既是“单元”类型的名称,也是该类型的唯一值

从命令式编程到Haskell的过程中令人困惑的一点是,语言处理“无”概念的方式是不同的。更令人困惑的是词汇,因为命令式语言和Haskell使用术语“void”来表示完全不同的事情

在命令式语言中,“函数”(可能不是真正的数学函数)的返回类型可能是“void”,如下伪代码示例所示:

void sayHello() {
    printLn("Hello!");
}
在这种情况下,
void
意味着“函数”如果返回,将不会产生结果值。(另一种可能性是,它们的函数可能不会返回,它可能永远循环,或者由于错误或异常而失败。)

然而,在Haskell中,所有函数(和
IO
actions)都必须产生一个结果。因此,当我们编写一个不产生任何有趣的返回值的
IO
操作时,我们让它返回
()

以后的操作将忽略
()
结果值

现在,您可能不需要太担心这一点,但是有一个地方会让人困惑,那就是,它意味着与命令式编程完全不同的东西
void
。因此,在比较Haskell语言和命令式语言时,“void”一词就成了一个雷区,因为在切换范式时,其含义完全不同

在Haskell中,
Void
是一种没有任何值的类型。这样做的最大后果是,在Haskell中,返回类型为
Void
的函数永远不会返回,它只能失败并出现错误或循环。为什么?因为函数必须生成一个类型为
Void
的值才能返回,但是没有这样的值

然而,在你使用一些更先进的技术之前,这是不相关的,所以你不需要担心它,只需要小心“void”这个词

但更重要的教训是,命令式和哈斯克尔的“无回报价值”概念是不同的。Haskell区分了:

  • 可能返回但其结果不包含任何信息的内容(类型为
    ()
  • 无法返回的内容,无论是什么(类型为
    Void
    type)

  • 命令
    void
    对应于前者,而不是后者。

    谢谢。然后,它意味着什么?它意味着monad
    IO
    ,它只能包含一个东西-
    )类型的
    )@cibercitizen1
    IO
    是一个类型构造函数,它接受一个类型并给出另一个类型(比如
    []
    ,它接受任何类型并“生成”列表)
    IO()
    是应用于()的
    IO
    类型构造函数,在某种程度上表示
    putChar
    不返回一元值(因为它总是返回相同的..)。@cibercitizen1看到我的编辑,他们应该有希望解释我将
    void
    的命令式编程概念与Haskell的
    ()
    如下:
    void
    是空记录的类型,即没有字段的记录。由于没有字段,任何两个空记录都非常相等,只是
    data Unit = Unit
    
    >>> :t Unit :: Unit
    Unit :: Unit
    >>> :t () :: ()
    () :: ()
    
    putStrLn :: String -> IO ()     -- the return type is unimportant,
                                    -- we just want the *effect*
    
    map (const ()) :: [a] -> [()]   -- this destroys all information about a list
                                    -- keeping only the *length*
    
    >>> [ (), (), () ] :: [()]      -- this might as well just be the number `3`
                                    -- there is nothing else interesting about it
    
    forward :: [()] -> Int          -- we have a pair of isomorphisms even
    forward = length
    
    backward :: Int -> [()]
    backward n = replicate n ()
    
    void sayHello() {
        printLn("Hello!");
    }
    
    sayHello :: IO ()
    sayHello = putStrLn "Hello!"