gpt4 book ai didi

haskell - 有没有办法在纯函数式语言中调用两个函数(一个接一个)? (在非 io 模式下)

转载 作者:行者123 更新时间:2023-12-01 09:26:26 25 4
gpt4 key购买 nike

我试图理解纯函数式语言的执行顺序。

我知道在纯函数式语言中,没有必要的执行顺序。

所以我的问题是:

假设有两个函数。
我想知道我可以一个接一个地调用一个函数的所有方式(除了从另一个函数嵌套调用)(除了 io-mode)。

我想查看 Haskell 或伪代码中的示例。

最佳答案

如果函数完全独立并且在调用另一个函数时不使用其中一个的结果,则无法执行您所描述的操作。

这是因为没有理由这样做。在无副作用的设置中,调用一个函数然后忽略其结果与在调用该函数所需的时间内不做任何事情完全相同(留出内存使用量)。

可能是 seq x y将评估 x然后 y ,然后给你y作为其结果,但不保证此评估顺序。

现在,如果我们确实有副作用,例如如果我们在 Monad 或 Applicative 中工作,这可能很有用,但我们并没有真正忽略结果,因为隐式传递了上下文。例如,你可以做

main :: IO ()
main = putStrLn "Hello, " >> putStrLn "world"

在 IO Monad 中。另一个示例是列表 Monad(可以将其视为表示非确定性计算):
biggerThanTen :: Int -> Bool
biggerThanTen n = n > 10

example :: String
example = filter biggerThanTen [1..15] >> return 'a' -- This evaluates to "aaaaa"

请注意,即使在这里我们也没有真正忽略结果。我们忽略特定的值,但我们使用结果的结构(在第二个示例中,结构是来自 filter biggerThanTen [1..15] 的结果列表具有 5 个元素的事实)。

不过,我应该指出,以这种方式排序的事物不一定按照它们的编写顺序进行评估。您可以通过 list Monad 示例看到这一点。不过,这在更大的例子中变得更加明显:
example2 :: [Int]
example2 =
[1,2,3] >>=
(\x -> [10,100,1000] >>=
(\y -> return (x * y))) -- ==> [10,100,1000,20,200,2000,30,300,3000]

这里的主要内容是评估顺序(在没有 IO 和忽略底部等副作用的情况下)不会影响 Haskell 中代码的最终含义(除了可能的效率差异,但这是另一个主题)。因此,永远没有理由以问题中描述的方式“一个接一个”地调用两个函数(即,调用彼此完全独立)。

做符号

Do 表示法实际上完全等同于使用 >>=>> (实际上还涉及另一件事来处理模式匹配失败,但这与手头的讨论无关)。编译器实际上采用 do 表示法编写的内容并将它们转换为 >>=>>通过一个称为“脱糖”的过程(因为它去除了语法糖)。以下是上面用 do 符号编写的三个示例:

IO 示例
main :: IO ()
main = do
putStrLn "Hello, "
putStrLn "World"

第一个列表示例
biggerThanTen :: Int -> Bool
biggerThanTen n = n > 10

example :: String -- String is a synonym for [Char], by the way
example = do
filter biggerThanTen [1..15]
return 'a'

第二个列表示例
example2 :: [Int]
example2 = do
x <- [1,2,3]
y <- [10,100,1000]
return (x * y)

以下是转换的并排比较:
do          --
m -- m >> n
n --


do --
x <- m -- m >>= (\x ->
... -- ...)

理解do符号最好的方法是先了解 >>=return因为,正如我所说,这就是编译器将 do 符号转换成的内容。

作为旁注, >>>>= 相同,它只是忽略了它的左参数的“结果”(尽管它保留了“上下文”或“结构”)。所以 >>的所有定义必须等于 m >> n = m >>= (\_ -> n) .

扩展 >>=在第二个列表示例中

为了帮助说明 Monads 通常不是不纯的这一点,让我们扩展 >>=在第二个列表示例中调用,使用列表的 Monad 定义。定义是:
instance Monad [] where
return x = [x]
xs >>= f = concatMap f xs

我们可以转换 example2进入:

第 0 步(我们已有的)
example2 :: [Int]
example2 =
[1,2,3] >>=
(\x -> [10,100,1000] >>=
(\y -> return (x * y)))

第 1 步(转换第一个 >>= )
example2 =
concatMap
(\x -> [10,100,1000] >>=
(\y -> return (x * y)))
[1,2,3]

步骤 2
example2 =
concatMap
(\x -> concatMap
(\y -> return (x * y))
[10,100,1000])
[1,2,3]

步骤 3
example2 =
concatMap
(\x -> concatMap
(\y -> [x * y])
[10,100,1000])
[1,2,3]

所以,这里没有魔法,只是普通的函数调用。

关于haskell - 有没有办法在纯函数式语言中调用两个函数(一个接一个)? (在非 io 模式下),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22964750/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com