作为一个让我熟悉Haskell的简单练习,在Youtube闲逛并绊倒美国倒计时游戏节目之后,我想为Numbers游戏做一个求解器。
你得到6个数字,需要将它们与(+) (-) (*) (/)
合并才能获得给定的结果。
到目前为止我得到的是脑死亡,
let operands = [75, 2, 6, 3, 8, 7] :: [Double]
let goal = 623 :: Double
let operations = [(+), (-), (*), (/)]
show (head [(a, x, b, y, c, z, d, t, e) |
a <- operands,
b <- filter (\ q -> q /= a) operands,
c <- filter (\ q -> q /= a && q /= b) operands,
d <- filter (\ q -> q /= a && q /= b && q /= c) operands,
e <- filter (\ q -> q /= a && q /= b && q /= c && q /= d) operands,
x <- operations,
y <- operations,
z <- operations,
t <- operations,
t (z (y (x a b) c) d) e == goal])
...但显然Show不知道如何处理函数。
No instance for (Show (Double -> Double -> Double))
arising from a use of `show'
Possible fix:
add an instance declaration for (Show (Double -> Double -> Double))
我该如何解决这个问题?我是否需要使用类型和数据构造函数来创建我自己的可以打印的函数,或者是否有更简单的方法呢?
答案 0 :(得分:14)
另一种选择:
data Operation = Add | Subtract | Multiply | Divide deriving (Show)
apply :: Operation -> Double -> Double -> Double
apply Add = (+)
apply Subtract = (-)
apply Multiply = (*)
apply Divide = (/)
答案 1 :(得分:9)
我通常不会建议您为函数实现Show
实例。由于这个原因,这不是“haskelly”做事的方式:
您定义了一种显示功能的“规范”方式。您可能希望它们现在显示为其名称,但如果您决定这样做会怎样:
add 0 y = y
add x y = add (x - 1) (y + 1)
operations = [..., add, ...]
您的程序输出真的会根据您的内部实现而改变吗?这没有多大意义。此外,无名功能会发生什么?
此外,在程序的另一部分中,您可能希望将您的函数显示为其类型等,然后您将有相互冲突的Show
实例。
通常情况下,只有在知道应该只有一种方式显示该内容时才实现Show
,并且这种方式适用于需要显示的所有值。
解决此问题的最简单方法可能是将操作名称与操作一起存储。像这样:
let operations = [("+", (+)), ("-", (-)), ("*", (*)), ("/", (/))]
-- ...
show (head [(a, xname, b, yname, c, zname, d, tname, e) |
a <- operands,
b <- filter (\ q -> q /= a) operands,
c <- filter (\ q -> q /= a && q /= b) operands,
d <- filter (\ q -> q /= a && q /= b && q /= c) operands,
e <- filter (\ q -> q /= a && q /= b && q /= c && q /= d) operands,
(xname, x) <- operations,
(yname, y) <- operations,
(zname, z) <- operations,
(tname, t) <- operations,
t (z (y (x a b) c) d) e == goal])
答案 2 :(得分:1)
你不能在Haskell中打印一个函数的名称(可能有一些关于元编程的疯狂技巧,但基本上你不能)。对于您的程序,最简单的方法是将操作列表定义为带有每个运算符名称字符串的对列表,例如。
let operations = [((+)," + "), ((-), " - ")), ((*), " * ")), ((/), " / ")]
您可以通过map fst operations
和map snd operations
获取他们的名字来获取操作列表。