【问题标题】:How do I declare the signature of a function that must return one of its arguments? (in any language*)如何声明必须返回其参数之一的函数的签名? (任何语言*)
【发布时间】:2019-07-02 02:28:45
【问题描述】:

如何表达function 的签名,必须返回它接收(被调用)的参数(或this),在 TypeScript 中 ? 有没有一种编程语言可以做到这一点?*

// In TypeScript (or consider it pseudo-code)
class C {
  // EXAMPLE 1 – Not polymorphic
  chainable(x): this                 // MUST not only return some C,
  {}                                 // but the same instance it was called on
}
// EXAMPLE 2
function mutate<T>(a: T[], x): T[]   // MUST return a, not a new Array
{
  /* So that this doesn't compile */ return Array.from(a);
  /* But this is OK */               return a;
}

相反,必须返回一个新实例的function 怎么样?

// EXAMPLE 3
function slice<T>(a: T[], x, y): T[] // MUST return a new Array

❌TypeScript


去 2?

下面的contract会实现上述吗?

contract referentiallyIdentical(f F, p P) {
  f(p) == p
  v := *p
}
type returnsSameIntSlice(type T, *[]int referentiallyIdentical) T
func main() {
  var mutate returnsSameIntSlice = func(a *[]int) *[]int {
    b := []int{2}
    /* Would this compile? */ return &b
    /* This should */         return a
  }
}  

C++20?

以上可以表示为C++concept吗?


✅斯卡拉


*最初,问题是关于在 TypeScript 中执行此操作,但由于这是不可能的,我很好奇它是否是另一种语言。

如果该语言的类型系统不能表达这一点,请随意删除标签

【问题讨论】:

  • 恐怕返回只会匹配签名,它不会匹配确切的对象。
  • 我认为 TypeScript 不支持您的要求。您正在定义返回值的 type,而不是 value 本身。我很想被证明是错误的。
  • 这通常是您在测试套件中检查的内容(例如assertEquals(a, sortInPlace(a))
  • @MTCoster 是的,但最好将其表达为类型签名的一部分。一些内置的 JavaScript 方法也可以这样工作
  • @Barry 这不是可以用 C++20 表达的东西吗contracts?

标签: scala go flowtype type-systems


【解决方案1】:

你可以 - 在 Scala 中。

带有返回this.type的方法的类:

class C {
  var x = 0 

  /** Sets `x` to new value `i`, returns the same instance. */
  def with_x(i: Int): this.type = {
    x = i
    this   // must be `this`, can't be arbitrary `C`
  } 
}

保证返回完全相同的数组的就地排序(这里实际上不排序):

def sortInPlace[A: Ordered](arr: Array[A]): arr.type = {
  /* do fancy stuff with indices etc. */
  arr
}

如果你尝试返回不同的数组,

def badSortInPlace(arr: Array[Int]): arr.type = Array(1, 2, 3) // won't compile

你会在编译时得到一个错误:

error: type mismatch;
found   : Array[Int]
required: arr.type
      def badSortInPlace(arr: Array[Int]): arr.type = Array(1, 2, 3)
                                                           ^

这称为singleton type, and is explained in the spec

【讨论】:

  • @pete Francis Gagné 基本上排除了 Rust。我认为你可以出于同样的原因排除 TypeScript——它也更加强调流敏感性。在这里,您需要依赖类型的特殊情况(其中类型取决于值)。但是您也可以排除纯函数式语言(即使是那些具有依赖类型的语言),因为在纯函数式语言中,返回完全相同值的函数将只是标识函数(因为一切都是不可变的)。你可能可以用 Agda 写,但是会有点枯燥(身份函数)。
【解决方案2】:

在具有参数多态性的语言中,任何类型的函数

a → a

必须是恒等函数:由于该函数在a中是多态的,它不可能知道任何关于a的信息,特别是它不可能知道如何构造一个a .由于它也不接受世界值或IO monad 或类似的东西,因此它无法从全局状态、数据库、网络、存储或终端中获取值。它也不能删除该值,因为它必须返回一个a

所以,它唯一能做的就是返回传入的a

【讨论】:

  • 我认为这不是真的。以这个 OCaml 为例:let notId r = ref (!r)。而且,我的问题不一定是关于纯函数式语言
  • 另外,我的问题不是关于参数多态性(C.chainable 不是多态性的,我没有编辑它......)。无论如何,a ⇾ a 函数可以改变其参数的内容,然后返回它,假设 a 有约束,就像在我的示例中一样
  • @pete,在 Haskell 或 Elm 等静态类型的函数式语言中,a 不能 被变异,因为 a 代表任何和所有类型。该函数对其性质的信息为零,因此它所能做的就是返回它(这些语言中不存在突变)。
  • 好的,答案是"In a language with parametric polymorphism, any function of the type a → a must be the identity function"。对于大多数具有参数多态性的语言来说,情况并非如此。 C#(具有参数多态性的语言)中的示例:class C&lt;T&gt; where T : new() { T fn(T a) { return new T(); } }。在没有通用方法来构造给定类型的实例的语言中,这是真的。我不知道 Haskell & Elm。
  • @pete:在您发布的 C♯ 示例中,它的工作原理正是因为它不是参数多态性,它是有界多态性,特别是,您有绑定new(),它将允许的类型限制为仅具有零参数构造函数的类型。换句话说,您可以构造一个新的T,因为您已经向它添加了一个额外的可构造约束。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-26
  • 2012-03-02
  • 2021-08-08
  • 1970-01-01
  • 2019-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多