我在思考像 Ruby 这样的纯面向对象语言,其中所有东西,包括数字、整数、浮点数和字符串本身都是对象。纯函数式语言也是这样吗?例如,在 Haskell 中,数字和字符串也是函数吗?
我知道 Haskell 是基于 λ 演算的,它将所有东西,包括数据和操作,表示为函数。对我来说似乎很合理,一个“纯函数式语言”会将所有东西都建模为函数,并且遵循函数必须始终返回相同输出的定义,且没有状态。
我在思考像 Ruby 这样的纯面向对象语言,其中所有东西,包括数字、整数、浮点数和字符串本身都是对象。纯函数式语言也是这样吗?例如,在 Haskell 中,数字和字符串也是函数吗?
我知道 Haskell 是基于 λ 演算的,它将所有东西,包括数据和操作,表示为函数。对我来说似乎很合理,一个“纯函数式语言”会将所有东西都建模为函数,并且遵循函数必须始终返回相同输出的定义,且没有状态。
从理论上讲考虑这是可以的,但是...
就像Ruby不是所有东西都是对象(例如参数列表不是对象),在Haskell中并不是所有东西都是函数。
欲了解更多相关信息,请查看这篇精彩的文章:http://conal.net/blog/posts/everything-is-a-function-in-haskell
@wrhall给出了一个好的答案。但你也有一定的正确性,在纯λ演算中一切都是函数是一致的,这种语言是图灵完全的(能够表达任何Haskell等语言能表达的纯计算)。
这带来了一些非常奇怪的事情,因为你可以对任何东西进行的唯一操作就是将其应用于另一些东西。你有一些值f
并想了解它的一些信息,你唯一的选择就是将它应用于某个值x
以得到f x
,这是另一个函数,唯一的选择是将其应用于另一个值y
,以此类推得到f x y
等等。
通常我会将纯λ演算解释为对不是函数的东西进行变换,但只能表达函数本身。也就是说,我可以创建一个函数(使用一些Haskelly语法糖来实现递归和let):
purePlus = \zero succ natCase ->
let plus = \m n -> natCase m n (\m' -> plus m' n)
in plus (succ (succ zero)) (succ (succ zero))
在这里,我表达了计算2+2
,而不需要知道非函数的存在。我只是将我定义的函数所需的参数作为参数,并且这些参数的值可以是church编码或者它们可以是“真实”的数字(无论那意味着什么)——我的定义并不关心。
您也可以认为Haskell是同样的情况。没有特别的理由认为有东西不是函数,也没有特别的理由认为一切都是函数。但是Haskell的类型系统至少可以防止您将参数应用于数字(任何想到fromInteger
的人现在都需要闭上嘴巴!:-))。在上述解释中,这是因为数字不一定被建模为函数,因此您不一定可以将参数应用于它们。
如果现在还不清楚,那么这整个答案都是一个技术/哲学的离题,而您问题的简单答案是“不,不是所有功能语言都是函数。函数就是您可以将参数应用于的东西,仅此而已。”
IO
单子和一些 IO
原语集合... - Luis Casillasinstance Num (a -> b)
,它和Haskell相关,但是相对较为离题。 - luquilet plus = \m n -> natCase m n (\m' -> plus m' (succ n))
吗?另外,也许更好的命名方式是 pure_2Plus2
? - Will Ness-- | A list corresponds to a function of this type:
type ChurchList a r = (a -> r -> r) --^ how to handle a cons cell
-> r --^ how to handle the empty list
-> r --^ result of processing the list
listToCPS :: [a] -> ChurchList a r
listToCPS xs = \f z -> foldr f z xs
该函数以具体列表为起点,但这并非必需。您可以使用纯函数来构建 ChurchList
函数:
-- | The empty 'ChurchList'.
nil :: ChurchList a r
nil = \f z -> z
-- | Add an element at the front of a 'ChurchList'.
cons :: a -> ChurchList a r -> ChurchList a r
cons x xs = \f z -> f z (xs f z)
foldChurchList :: (a -> r -> r) -> r -> ChurchList a r -> r
foldChurchList f z xs = xs f z
mapChurchList :: (a -> b) -> ChurchList a r -> ChurchList b r
mapChurchList f = foldChurchList step nil
where step x = cons (f x)
filterChurchList :: (a -> Bool) -> ChurchList a r -> ChurchList a r
filterChurchList pred = foldChurchList step nil
where step x xs = if pred x then cons x xs else xs
最后一个函数使用了Bool
,但是当然我们也可以用函数替换Bool
:
-- | A Bool can be represented as a function that chooses between two
-- given alternatives.
type ChurchBool r = r -> r -> r
true, false :: ChurchBool r
true a _ = a
false _ b = b
filterChurchList' :: (a -> ChurchBool r) -> ChurchList a r -> ChurchList a r
filterChurchList' pred = foldChurchList step nil
where step x xs = pred x (cons x xs) xs
()
类型,(- >)
和IO
类型构造函数,return
和>> =
用于IO
,以及一组合适的IO
原语。这显然是非常不切实际的,并且性能会更差(尝试编写tailChurchList :: ChurchList a r -> ChurchList a r
以了解其中的滋味)。()
?它有一个完全合理的 Church 编码,即 id
。 - C. A. McCann1 我所知道的所有“纯面向对象”的语言都存在一些边角情况,但这并不是很有趣。很明显,在那些1
是某个类的实例,而且该类可以被子类化的语言中,对象比在1
不是对象的语言中更加深入。
2 所有计算都涉及到表示。计算机什么也不知道,只有我们用来表示数字的位模式和恰好与数字操作对应的位模式操作(因为我们设计它们如此)。
3 这也不是根本的问题。您可以设计一个“纯”面向对象的语言,以这种意义上的纯形式。我倾向于编写大部分OO代码以保持纯洁。
4 如果这看起来晦涩难懂,您可能会反思在其他上下文中,“功能性”,“对象”和“语言”这些术语具有极其不同的含义。
getChar :: IO Char
是一个函数还是不是?Haskell报告没有给出定义。但它指出getChar
是一个函数(参见这里)。(好吧,至少我们可以说它是一个函数。)
所以我认为答案是是的。
我认为除了"一切都是函数"之外,很难有"函数"的正确定义。(什么是"正确定义"?好问题...)考虑下面的例子:
{-# LANGUAGE NoMonomorphismRestriction #-}
import Control.Applicative
f :: Applicative f => f Int
f = pure 1
g1 :: Maybe Int
g1 = f
g2 :: Int -> Int
g2 = f
f
是函数还是数据类型?这要看情况。
g1
不是一个函数,而g2
是;f
是一个多态值,可以在特定上下文中用作函数。像任何多态值一样,它的不同单态实例将具有不同的属性,但当您操作“完全通用”的f
时,您无法访问其中任何一个,因为它们不适用于所有上下文中的f
。 “成为函数”的属性并不比“成为列表”更特殊;g3 = f :: [Int]
并没有显示“所有东西都是列表”,g2
也没有显示“所有东西都是函数”。 - BengetChar :: IO Char
这一事实来判断的,那我可以指出,在几段话之后,他们明确说了“getChar操作”,但也提到了“interact函数”。 - Vitusf::() -> B
和g::B
(尽管它们是同构的)。 - Vitus