Haskell 中类型为 a -> b 的函数?
Function with type a -> b in Haskell?
Haskell 中是否有类型为 a -> b
的函数?这意味着,是否可以编写一个 f :: a -> b
的函数?我认为这样的函数不存在,原因如下:假设我们在 f :: a -> b
处找到 f,f 2
会产生什么? b
类型的值,但是 b
是什么,因为 Haskell 无法从我给出的参数中推断(我认为)它?这个对吗?否则,你能给我一个这样的功能的例子吗?
有,我认为,正是一个,但它有点作弊:
> let f _ = undefined
> :t f
f:: t -> t1
之所以存在,是因为 bottom 被认为是每种类型的值。
Barring ⊥ (bottom value – undefined
etc.),总是可以的,但永远用不上,确实不可能有这个功能。这是我们从多态类型签名中获得的所谓 free theorems 的最简单实例之一。
您凭直觉解释了为什么这是不可能的,但最终失败了,您走在了正确的轨道上。是的,可以考虑f (5 :: Int)
。问题是 而不是 编译器“无法推断” b
会是什么——许多实际函数都是这种情况,例如
fromIntegral :: (Num b, Integral a) => a -> b
很有道理; b
将从使用 fromIntegral x
的环境 中推断出 。例如,我可能会写†
average :: [Double] -> Double
average l = sum l / fromIntegral (length l)
在这种情况下,length l :: a
具有固定类型 Int
,而 fromIntegral (length l) :: b
必须具有固定类型 Double
才能适应环境,这与大多数其他情况不同具有类型推断的语言,来自环境的信息在此可用基于 Hindley-Milner 的语言。
不,f :: a -> b
的问题在于您可以将 a
和 b
实例化为 任何 荒谬的类型组合,而不仅仅是不同的数字类型。因为 f
是不受约束的多态性,所以它必须能够将 任何类型转换为任何其他类型 .
特别是可以转换成空类型 Void
.
evil :: Int -> Void
evil = f
然后我可以
muahar :: Void
muahar = f 0
但是,根据 Void
的构造, 不能 是这种类型的值(除了 ⊥ 之外,你无法在不崩溃或无限循环的情况下进行计算).
†需要注意的是,根据某些标准,这并不是计算平均值的好方法。
... but what is b
since Haskell cannot infer it from the arguments I gave?
根据上下文,Haskell可以推断出return类型;说:
{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances #-}
class Cast a b where
cast :: a -> b
instance Cast a a where
cast = id
instance Cast Int String where
cast = show
instance Cast Int Double where
cast = fromIntegral
然后,
cast :: Cast a b => a -> b
如果给出足够的上下文,Haskell 知道要使用哪个函数:
\> let a = 42 :: Int
\> let b = 100.0 :: Double
\> "string: " ++ cast a -- Int -> String
"string: 42"
\> b * cast a -- Int -> Double
4200.0
为了实现f :: a -> b
,这意味着f
必须能够return任何可能的类型。即使是今天不存在但有人可以在十年后定义的类型。如果没有某种反射功能,那显然是不可能的。
嗯..."impossible" 是个大词...正如其他答案指出的那样,不可能排除底部。换句话说,f
永远不会 return 类型为 b
的值。它 可以 抛出异常,或者永远循环。但是(可以说)这些东西都不是真正的 "returning a value".
f1 :: a -> b
f1 = error "f1"
f2 :: a -> b
f2 s = error "f2"
f3 :: a -> b
f3 x = f3 x
这些函数都略有不同,而且它们都编译得很好。而且,当然,它们都是无用的! 所以是的,没有 有用的 类型为 a -> b
.[=26 的函数=]
如果要分头发:
f1
抛出异常。
f1 'x'
抛出异常。
f2
是一个看起来很正常的函数。
f2 'x'
抛出异常。
f3
是一个看起来很正常的函数。
f3 'x'
不会抛出异常,但它会永远循环,所以它实际上从来没有 returns 任何东西。
基本上,您看到 returns "any type" 的任何函数都是实际上从未 returns 的函数。我们可以在不寻常的单子中看到这一点。例如:
f4 :: a -> Maybe b
完全有可能实现这个函数而不抛出异常或永远循环。
f4 x = Nothing
同样,我们实际上并不是 return b
。我们可以类似地做
f5 :: a -> [b]
f5 x = []
f6 :: a -> Either String b
f6 x = Left "Not here"
f7 :: a -> Parser b
f7 x = fail "Not here"
Haskell 中是否有类型为 a -> b
的函数?这意味着,是否可以编写一个 f :: a -> b
的函数?我认为这样的函数不存在,原因如下:假设我们在 f :: a -> b
处找到 f,f 2
会产生什么? b
类型的值,但是 b
是什么,因为 Haskell 无法从我给出的参数中推断(我认为)它?这个对吗?否则,你能给我一个这样的功能的例子吗?
有,我认为,正是一个,但它有点作弊:
> let f _ = undefined
> :t f
f:: t -> t1
之所以存在,是因为 bottom 被认为是每种类型的值。
Barring ⊥ (bottom value – undefined
etc.),总是可以的,但永远用不上,确实不可能有这个功能。这是我们从多态类型签名中获得的所谓 free theorems 的最简单实例之一。
您凭直觉解释了为什么这是不可能的,但最终失败了,您走在了正确的轨道上。是的,可以考虑f (5 :: Int)
。问题是 而不是 编译器“无法推断” b
会是什么——许多实际函数都是这种情况,例如
fromIntegral :: (Num b, Integral a) => a -> b
很有道理; b
将从使用 fromIntegral x
的环境 中推断出 。例如,我可能会写†
average :: [Double] -> Double
average l = sum l / fromIntegral (length l)
在这种情况下,length l :: a
具有固定类型 Int
,而 fromIntegral (length l) :: b
必须具有固定类型 Double
才能适应环境,这与大多数其他情况不同具有类型推断的语言,来自环境的信息在此可用基于 Hindley-Milner 的语言。
不,f :: a -> b
的问题在于您可以将 a
和 b
实例化为 任何 荒谬的类型组合,而不仅仅是不同的数字类型。因为 f
是不受约束的多态性,所以它必须能够将 任何类型转换为任何其他类型 .
特别是可以转换成空类型 Void
.
evil :: Int -> Void
evil = f
然后我可以
muahar :: Void
muahar = f 0
但是,根据 Void
的构造, 不能 是这种类型的值(除了 ⊥ 之外,你无法在不崩溃或无限循环的情况下进行计算).
†需要注意的是,根据某些标准,这并不是计算平均值的好方法。
... but what is
b
since Haskell cannot infer it from the arguments I gave?
根据上下文,Haskell可以推断出return类型;说:
{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances #-}
class Cast a b where
cast :: a -> b
instance Cast a a where
cast = id
instance Cast Int String where
cast = show
instance Cast Int Double where
cast = fromIntegral
然后,
cast :: Cast a b => a -> b
如果给出足够的上下文,Haskell 知道要使用哪个函数:
\> let a = 42 :: Int
\> let b = 100.0 :: Double
\> "string: " ++ cast a -- Int -> String
"string: 42"
\> b * cast a -- Int -> Double
4200.0
为了实现f :: a -> b
,这意味着f
必须能够return任何可能的类型。即使是今天不存在但有人可以在十年后定义的类型。如果没有某种反射功能,那显然是不可能的。
嗯..."impossible" 是个大词...正如其他答案指出的那样,不可能排除底部。换句话说,f
永远不会 return 类型为 b
的值。它 可以 抛出异常,或者永远循环。但是(可以说)这些东西都不是真正的 "returning a value".
f1 :: a -> b
f1 = error "f1"
f2 :: a -> b
f2 s = error "f2"
f3 :: a -> b
f3 x = f3 x
这些函数都略有不同,而且它们都编译得很好。而且,当然,它们都是无用的! 所以是的,没有 有用的 类型为 a -> b
.[=26 的函数=]
如果要分头发:
f1
抛出异常。f1 'x'
抛出异常。f2
是一个看起来很正常的函数。f2 'x'
抛出异常。f3
是一个看起来很正常的函数。f3 'x'
不会抛出异常,但它会永远循环,所以它实际上从来没有 returns 任何东西。
基本上,您看到 returns "any type" 的任何函数都是实际上从未 returns 的函数。我们可以在不寻常的单子中看到这一点。例如:
f4 :: a -> Maybe b
完全有可能实现这个函数而不抛出异常或永远循环。
f4 x = Nothing
同样,我们实际上并不是 return b
。我们可以类似地做
f5 :: a -> [b]
f5 x = []
f6 :: a -> Either String b
f6 x = Left "Not here"
f7 :: a -> Parser b
f7 x = fail "Not here"