ChatGPT 与 Groovy 一行代码
作者: Paul King
发布时间: 2023-10-19 06:00PM
我问 ChatGPT 是否可以将一些简短的/一行代码的编程相关冷笑话表示为简短的/一行代码的 Groovy 脚本。它最初的回答有点令人失望,但在一些强制和一些“后期制作调整”之后,这篇文章包含了结果。请注意,双关语的质量参差不齐。
但在开始之前,Groovy 是与基于云的生成式 AI 系统交互的绝佳语言。您可以查看以下 GitHub 仓库,它展示了如何使用 Groovy 和 Micronaut 与 ChatGPT 交谈。这个例子反过来是基于 Ken Kousen 在 Java 中的类似示例。查看他关于该主题的精彩 视频。还可以查看 Guillaume Laforge 最近关于使用 Groovy 通过其 PaLM 2 API 与 Google 的 Bard 交谈以及使用 LangChain4J 的文章。
话虽如此,我们只是为这篇文章使用了 Web UI。现在,让我们看看一些 PUNch 行…
我们可以使用以下 Groovy 脚本进行验证
def christmas = 25 // dec
def halloween = 031 // oct
assert christmas == halloween
我们可以使用以下 Groovy 脚本进行验证
assert 'Groovy' == 'Go'.take(1) + 'R'.toLowerCase() +
'Python'['Perl'.size()] * 2 +
'Java'['C#'.size()] + 'Ruby'[-1]
我们将 Expando
类与 Elvis 运算符和 Groovy 真值相结合来验证这个事实
def money = intelli = new Expando()
def rich = money.cache ?: intelli.cents ?: null?.stocks
assert !rich
我们创建了一个“可排序”的 Chocolate
记录,利用了默认参数和声明式增强。然后我们创建了一个 Box
类,它委托给 List
。然后我们创建了一盒巧克力,并使用 toString()
方法检查它是否“字母排序”
@Sortable @ToString(ignoreNulls = true)
record Chocolate(int cocoa, String filling = null) {}
class Box { @Delegate List<Chocolate> contents }
var box = new Box(contents: [
new Chocolate(80),
new Chocolate(50, 'Caramel')
].sort())
assert box.toString() == '[Chocolate(50, Caramel), Chocolate(80)]'
让我们使用 Groovy 的灵活索引对单词“melons”进行一些重新排列,看看我们是否能得到“lemons”
def dyslexic = 'melons'[2..0,3..-1] == 'lemons'
assert dyslexic
让我们创建一个 6:30 的 LocalTime
,并检查指针是否指向下方。分针在 60 分钟内移动 360 度,因此每分钟移动 6 度。我们可以检查 6:30 时,它是否指向正下方 (180°)。时针在 720 分钟(半天)内移动 360°,因此我们将总分钟数除以 2。总分钟数是小时数乘以 60 加上当前小时的分钟数。在 6:30,我们知道时针会移动到 6 和 7 之间的一半(15°),但为了测试,我们将确保它指向下方(我们将说它在直线下方 20° 内,我们将指定为一个范围)。以下是结果
def (h, m) = LocalTime.of(6, 30)[HOUR_OF_DAY, MINUTE_OF_HOUR]
assert 6 * m == 180L
assert (h * 60 + m).intdiv(2) in 180L..200L
为了用 Groovy 展示这一点,我们首先应该声明我们的无知和冷漠。然后我们计算差异,最后检查我们的断言
int ignorance, apathy
int know = care = ignorance - apathy
assert !know && !care
当然,运行这段脚本
def (first, second) = ['egg', 'chicken'].shuffled()
println "Which came first, the $first or the $second? The eternal debate!"
它实际上只是按两种不同的顺序提出问题,但我相信你明白我的意思。
由于死亡和税收是确定的,我们应该将关于它们的引言存储在一个不可变的结构中。记录提供浅层不变性,对于这种情况非常有用。对于深层不变性,请考虑使用 @Immutable
AST 转换,因此在这里,即使我们的引言存储在可变的 ArrayList 中,也无法更改它。以下是一个示例
record Quote(String text, String author, int year) { }
var q1 = new Quote('Perfection is immutable. But for things imperfect, change is the way to perfect them.', 'Owen Feltham', 1840)
var q2 = new Quote('Nothing is certain except death and taxes.', 'Benjamin Franklin', 1789)
@Immutable
class FavoriteQuotes { List<Quote> list }
var favorites = new FavoriteQuotes([q1, q2])
让我们使用特性来检查钻石和狗的最佳朋友
trait HasBestFriend {
abstract String friend()
boolean isBestFriend(String candidate) {
friend() == candidate
}
}
class Diamond implements HasBestFriend {
String friend() { 'girl' }
}
class Dog implements HasBestFriend {
String friend() { 'man' }
}
assert ['man', 'girl'].collect{
[new Diamond().isBestFriend(it),
new Dog().isBestFriend(it)]
} == [[false, true], [true, false]]
谁知道汽车和智能手机之间有什么关系,但趋势似乎是公司想要涉足这两个领域。同样,如果你有两个表面上毫无关系的类,Groovy 的鸭子类型,或者在这种情况下是属性处理,可能会让你比你想象的更容易地将它们组合在一起。
import groovy.transform.*
record Smartphone(String make, String model, String color, int year) { }
record Car(String make, String model, String color, int year) { }
def s = new Smartphone('Landrover', 'Explore', 'Black', 2018)
def c = new Car(s.toMap())
assert c.toString() == 'Car[make=Landrover, model=Explore, color=Black, year=2018]'
首先让我们看看 Groovy 如何帮助我们找到我们正在寻找的机器人。当有几个克隆体时,机器人是最难找到的。我们不会提到克隆人战争!
我们将创建一个机器人及其克隆体的随机列表,然后搜索我们想要的机器人
@AutoClone class Droid { String name }
def r2d2 = new Droid(name: 'R2-D2')
def c3po = new Droid(name: 'C-3PO')
def droids = [r2d2, c3po]
3.times {
droids << r2d2.clone()
droids << c3po.clone()
}
droids.shuffle()
droids.eachWithIndex { droid, index ->
if (droid == r2d2) println "Droid $index is $r2d2.name"
if (droid == c3po) println "Droid $index is $c3po.name"
}
如果我们不想输出找到机器人的索引,我们可以使用另一个表达式来表明我们想要的机器人已经找到了
assert droids.any{ it.is(r2d2) }
assert droids.any{ it.is(c3po) }
当然,欧比旺使用绝地武士的精神控制,我们可以使用一些 Groovy 元编程来展示这一点,在这种情况下,是一个类别类
class JediMindTrick {
static boolean is(Droid d, Droid other) { false }
}
use(JediMindTrick) {
assert !droids.any{ it.is(r2d2) }
assert !droids.any{ it.is(c3po) }
}
如这里所示
try {
pet.say('Pieces of 7')
} catch(ParrotyError e) {
var plank = e.stackTrace
plank.walk()
}
根据定义,纯函数始终对相同输入返回相同的结果。因此,对纯函数的一种可能的优化是为给定的输入值集缓存结果。Groovy 提供 @Memoized
AST 转换来执行此操作(以及用于闭包的 .memoized()
方法调用)。
让我们编写一个 StringUtil
类,它有一个几乎是纯函数。bothCases
方法的返回值就其输入而言是纯函数。它返回一个包含输入字符串的小写和大写值的列表。它还会在每次调用时增加一个计数器;这只是为了让我们了解发生了什么。
class StringUtil {
static int count = 0
@Memoized
static List<String> bothCases(String s) {
count++
[s.toLowerCase(), s.toUpperCase()]
}
}
我们将 @Memoized
注解应用于 bothCases
,这将启用自动缓存。该注解具有一些可选的注解属性,用于配置缓存行为,但我们将使用默认值。
我们可以看到,对于常量参数,'Foo' 在我们的案例中被调用了两次,没有必要在第二次调用时调用 bothCases
方法,因为我们可以使用上一次调用中缓存的值。
assert StringUtil.count == 0
assert StringUtil.bothCases('Foo') == ['foo', 'FOO']
assert StringUtil.count == 1
assert StringUtil.bothCases('Foo') == ['foo', 'FOO']
assert StringUtil.count == 1
println "Binary: It's as easy as ${(1..3).collect{ Integer.toBinaryString(it) }.join(', ')}"
assert 40 == Math.round(37/10)*10
String[] celebrate = ['hip', 'hip']