Haskell 括号()本身是什么意思?
我读了那本书 枚举成员是按顺序排列的类型此类中的类型: (),Bool,Char 它也出现在一些签名中:Haskell 括号()本身是什么意思?,haskell,parentheses,Haskell,Parentheses,我读了那本书 枚举成员是按顺序排列的类型此类中的类型: (),Bool,Char 它也出现在一些签名中: putChar :: Char -> IO () 在谷歌上很难找到关于它的信息,因为答案涉及到“公共括号”(用于函数调用、优先级问题等)的问题 因此,表达式()是什么意思?它是一种类型吗?什么是()类型的变量?用于什么以及何时需要它?它既是类型又是值()是一种特殊类型的“发音”单位,它有一个值:(),也是发音单位。它本质上与Java或C/C++中的类型void相同。如果您熟悉
putChar :: Char -> IO ()
在谷歌上很难找到关于它的信息,因为答案涉及到“公共括号”(用于函数调用、优先级问题等)的问题
因此,表达式
()
是什么意思?它是一种类型吗?什么是()
类型的变量?用于什么以及何时需要它?它既是类型又是值()
是一种特殊类型的“发音”单位,它有一个值:()
,也是发音单位。它本质上与Java或C/C++中的类型void
相同。如果您熟悉Python,可以将其视为具有singletonNone
的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
对应于前者,而不是后者。谢谢。然后,它意味着什么?它意味着monadIO
,它只能包含一个东西-(
)类型的(
)@cibercitizen1IO
是一个类型构造函数,它接受一个类型并给出另一个类型(比如[]
,它接受任何类型并“生成”列表)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!"