【问题标题】:Declare a function with no return value?声明一个没有返回值的函数?
【发布时间】:2018-05-15 03:42:21
【问题描述】:

我们可以用函数式语言创建一个带有 void(即没有返回值)的函数吗?喜欢 Haskell 或 Scheme

【问题讨论】:

  • 在 Haskell 中没有返回值的函数会做什么?
  • 我不确定我是否在关注这个问题。如果某些东西没有返回类型,为什么它是一个函数?
  • 有点。忽略实现细节,您可以将void 视为只有一个居民的返回类型。 Haskell 选择将这类事情明确化——我们的 void()
  • 和Java一样,我们有void方法。我们只是做一些操作,没有返回值
  • 在 Haskell 中不能进行这样的操作。它是一种纯粹的语言。没有返回值的函数(或返回 () 的函数,正如 Alec 所建议的)根本不会做任何事情。

标签: haskell functional-programming scheme


【解决方案1】:

首先,您需要记住,编程语言倾向于在不同于数学含义的意义上使用“函数”一词。编程语言函数只是一个命名的子例程,它可能产生也可能不产生可以分配或传递的值。

Pascal 在“真实”函数和不返回值的函数之间做了一些区分;关键字procedure 创建一个不返回任何内容的子例程,关键字function 必须返回某种类型的值。

C 是一个模糊这种区别的例子。一个函数可以有一个 void 类型的返回值,它实际上是具有 one 值的类型(尽管该值实际上并没有在代码中表示;你必须假装它存在)。每个具有这种返回类型的函数总是返回相同的值。 Python 使它更明确一点;没有return 语句的函数或没有值的return 语句实际上返回单例值None

Haskell 有一个类似的类型,(),它由一个同名的值组成。您当然可以定义一系列函数,每个类型一个函数 foo :: a -> () 忽略其参数并返回 ()。它没有任何实用价值(作为纯语言,函数不能做任何事情除了返回其声明的返回类型的值),但它确实有存在。 foo _ = ().

顺便提一下,a -> () 类型的函数将 () 建立为(伪)类别 Hask 中的 terminal 对象,这是建立 所必需的Hask 作为一个笛卡尔封闭的范畴,使其适合定义 Haskell 的语义。


然而,Haskell确实有一个包含 no 值的类型,恰当地称为Void

data Void

由于Void 是有效类型,您可以想象一个类型包含从Void 到任何其他类型的函数:

absurd :: Void -> a

但是,由于没有 Void 类型的值,因此您不能真正调用这样的函数。 Void -> a 类型的唯一函数可以定义为

absurd x = case x of {}  -- There's nothing x *can* match

这并不是说absurd 一点用处都没有,只是没有实际用处。正如a -> () 类型的函数将() 定义为Hask 中的终端对象,absurdVoid 定义为Haskinitial 对象/strong>。

(这个答案的后半部分是 Bartosz Milewski 精彩的一系列帖子Category Theory for Programmers 中的(糟糕的)信息概要。)

【讨论】:

  • absurd 实际上是Void -> a,而不是相反。 VoidHaskinitial 对象;终端对象是()
  • 叹息。这就是我试图从记忆中写出来的结果。
  • 另外,你可以定义absurd;基本上唯一的方法是(空但详尽!)案例匹配absurd x = case x of {}。这就是重点:只有一个函数Void -> a,就像只有一个函数a -> ()。这是初始/终端对象的要求。
  • 是的,absurd 的定义非常明确,本身并不荒谬。实际上调用它的含义是荒谬的,如果没有“作弊”,你就无法做到这一点,因为你需要首先获得Void类型的值。
【解决方案2】:

在 Haskell 中,唯一函数的事情是返回一个值。

如果一个函数没有返回任何东西,那么它到底做了什么

您可能正在考虑诸如打印“函数”之类的东西,它打印出一些东西并且什么都不返回。但这不是数学函数,这是一个动作。 Haskell 以完全不同的方式(即 monad)对它们进行建模。如果你想知道那是什么,Stack Overflow 上有 100 亿次关于它的讨论,并且散落在互联网上。

【讨论】:

    【解决方案3】:

    在 Racket 中,您可以:

    Welcome to DrRacket, version 6.11 [3m].
    Language: racket, with debugging; memory limit: 128 MB.
    > (define (f) (displayln "hello") (void))
    > (f)
    hello
    > (void? (f))
    hello
    #t
    

    【讨论】:

      【解决方案4】:

      在 Haskell 中,您可以编写一整套返回 () (unit) 的函数,相当于 C 语言中的 void

      foo :: a -> ()
      foo _ = ()
      
      bar :: a -> b -> ()
      bar _ _ = ()
      

      不过,您会注意到,我的实现忽略了他们的输入,只是简单地返回(),所以他们什么都不做

      你可以这样称呼他们:

      Prelude> foo 42
      ()
      Prelude> bar 42 "foo"
      ()
      

      但这仍然没有完成任何事情。

      另一方面,您可以编写返回 IO () 的函数,如下所示:

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

      但这现在是不纯的。虽然这会产生副作用,但您可以争论它是否有效。至少,在 Haskell 中,您不能从纯代码中调用不纯代码(这是设计使然),因此它不会组合。

      【讨论】:

      • 我认为void 的函数和多态空数据构造函数之间存在联系。可以将Nothing 视为从类型到() 的函数。
      【解决方案5】:

      这样一个函数的目的是什么?另外,如果您想到一个数学函数(函数式编程的基础),那么这个函数的共域是什么?

      因此,haskell 的简短回答是否定的(我不知道足够的方案来给出一个明智的答案)。

      在 haskell 中最接近 void 的东西是 IO ()

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-04
        • 2010-11-30
        • 2021-05-30
        • 2015-09-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多