首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Raku:返回类型

Raku:返回类型
EN

Stack Overflow用户
提问于 2021-09-04 07:29:47
回答 3查看 162关注 0票数 7

我想写一个函数,返回一个数组,其所有子数组的长度必须为2。例如,return将为[[1, 2], [3, 4]]

我定义:

(1) subset TArray of Array where { .all ~~ subset :: where [Int, Int] }

代码语言:javascript
运行
复制
sub fcn(Int $n) of TArray is export(:fcn) {
    [[1, 2], [3, 4]];
}

我发现(1)过于复杂。有没有更简单的东西?

EN

回答 3

Stack Overflow用户

发布于 2021-09-04 08:21:36

先退一步

代码语言:javascript
运行
复制
subset TArray of Array where { .all ~~ subset :: where [Int, Int] };

有没有更简单的东西?

在我们开始之前,让我们退后一步。即使仅仅看一下代码就忽略了它的“过于复杂”的性质,由于各种可能不那么明显的原因,它也有潜在的问题和复杂性。我将重点介绍三点:

  • subset将接受包含Arrays的Array,其中每个数组包含两个Ints。但它不强制使用Array[Array[Int]]。外部Array的类型可能只是一个泛型Array,而不是一个让Array[Array[Int]]单独存在的Array[Array]。事实上,除非您有意引入强类型的值,否则它将是。我将在本答案的最后一节介绍强类型。

  • 如果是空的Array呢?你的subset会接受的。这就是你的意图吗?如果不是,那么至少需要一对Ints?

怎么办?

从简单开始

Raku在让简单的事情变得简单方面做得很好。如果我们把对强类型的人为需求放在一边,把重点放在用来紧凑代码的简单工具上,我在过去建议的一个简单的子集是:

代码语言:javascript
运行
复制
subset TArray where .all == 2; # BAD despite being idiomatic???

这具有原始代码所具有的所有问题,此外,它还接受整数所属的非整数的数据。

但是它确实有一个可取之处,那就是它做了一个有用的检查(内部数组每个都有两个元素),而且它比你的代码简单得多。

现在我提醒自己,我需要将~~左侧的.all视为可能存在的问题,我将改写为:

代码语言:javascript
运行
复制
subset TArray where 2 == .all; # Potentially the new idiomatic.

这个版本读起来更差,但是,虽然可读性很重要,但基本的正确性更重要。

仍然相当简单,问题也很少。

下面是我想出的两个变体:

代码语言:javascript
运行
复制
subset TArray where all .map: * ~~ (Int,Int);
subset TArray where .elems == .grep: (Int,Int);

这都避免了连接/smartmatch问题。(第一个where表达式在智能匹配的左侧确实有一个交叉点,但它不是问题的示例。)

第二个版本显然不是那么正确(可以把它看作是检查子数组的计数与匹配(Int,Int)的子数组的计数是否相同),但它很好地解决了存在零子数组时的匹配问题,如果需要修复的话:

代码语言:javascript
运行
复制
subset TArray where 0 < .elems == .grep: (Int,Int);

强类型解决方案

到目前为止,解决方案还没有处理强类型。也许这是可取的。也许不是。

为了理解我的意思,让我们先来看看字面量:

代码语言:javascript
运行
复制
say WHAT 1;             # (Int)
say WHAT [1,2];         # (Array)
say WHAT [[1,2],[3,4]]; # (Array)

这些值具有由其文字constructors.确定的类型

  • 后两个只是Array,它们的元素是泛型的。

(第二个不是Array[Int],这可能是意料之中的。类似地,最后一个不是Array[Array[Int]]。)

当前内置的复合类型(数组和散列)的Raku文字形式都构造泛型Array,它们不限制其元素的类型。

请参阅PR Introduce [1,2,3]:Int syntax #4406,了解有关元素类型复合文字的提案/ PR,以及有关该PR的替代和/或补充方法的a related issue I just posted in response to your Q here。(多年来一直在讨论类型系统的这一方面,但现在似乎是Rakoons考虑解决这个问题的时候了。)

如果您想构建一个强类型的数据结构作为从例程中返回的值,并让返回类型对此进行检查,该怎么办?

下面是构建这样一个强类型值的一种方法:

代码语言:javascript
运行
复制
my Array[Array[Int]] $result .= new: Array[Int].new(1,2), Array[Int].new(3,4);

超级冗长!但是现在你可以为你的sub的返回类型检查写下下面的代码,它就可以工作了:

代码语言:javascript
运行
复制
subset TArray of Array[Array[Int]] where 0 < .elems == .grep: (Int,Int);

sub fcn(Int $n) of TArray is export(:fcn) {
  my Array[Array[Int]] $result .= new: Array[Int].new(1,2), Array[Int].new(3,4);
}

构建强类型值的另一种方法是不仅在变量的类型约束中指定强类型,而且还指定从松散类型值到强类型目标的。

我们保持完全相同的subset (它建立了强类型的目标数据结构并添加了“细化类型”检查):

代码语言:javascript
运行
复制
subset TArray of Array[Array[Int]] where 0 < .elems == .grep: (Int,Int);

但是,我们没有使用冗长的按构造更正的初始化值,而是使用完整的类型名和new,我们引入了额外的强制类型,然后只使用普通的文字语法:

代码语言:javascript
运行
复制
constant TArrayInitialization = TArray(Array[Array[Int]()]());

sub fcn(Int $n) of TArray is export(:fcn) {
  my TArrayInitialization $result = [[1,2],[3,4]];
}

(我本可以将TArrayInitialization声明作为另一个subset编写,但这样做有点夸张。constant可以轻松地完成这项工作。)

票数 7
EN

Stack Overflow用户

发布于 2021-09-05 15:23:23

我猜测其目的是将内部数组的类型限制为Int,Int…我能做到的最接近的方法是声明两个子集,一个基于另一个子集。

代码语言:javascript
运行
复制
subset IArray where * ~~ [Int, Int];
subset TArray where .all ~~ IArray;

否则,你使用的匿名子集形式似乎是最简短的,尽管@raiph指出你可以去掉'of Array‘这一部分。

票数 3
EN

Stack Overflow用户

发布于 2021-09-07 15:57:22

如果你想对一个函数的参数(而不是它的返回类型)施加这样的约束,你可以这样做:

代码语言:javascript
运行
复制
sub fcn(@a where {all .map: * ~~ [Int, Int]}) {...}

正如其他答案所提到的,目前还没有很好的语法来类似地约束返回类型,但有一个建议是使用add support for similar syntax for return types。事实上,正如在那个问题中提到的,有人自愿致力于实现,但据我所知还没有取得任何进展。(我想我应该知道,因为我是那个志愿者…(哦)

因此,就目前而言,子集是最好的选择-但希望将来会有更好的方法来编写它。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69053265

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档