How can I have Show display the name of a function?

混江龙づ霸主 提交于 2020-01-04 01:56:08

问题


As a simple exercise to get me acquainted with Haskell, after idling around on Youtube and stumbling into the American Countdown game show, I wanted to make a solver for the Numbers game.

You get 6 numbers and need to combine them with (+) (-) (*) (/) in order to get a given result.

What I've got so far is the very brain-dead,

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])

...but obviously Show doesn't know what to do with functions.

No instance for (Show (Double -> Double -> Double))
  arising from a use of `show'
Possible fix:
  add an instance declaration for (Show (Double -> Double -> Double))

How can I work around this? Do I need to mess with type and data constructors to make my own functions that can print or is there some easier way around it?


回答1:


I would generally not advise you to implement a Show instance for functions. It is not the "haskelly" way of doing things, for this reason:

You define a "canonical" way of showing functions. You might want them to be shown as their names now, but what if you decide to do this:

add 0 y = y
add x y = add (x - 1) (y + 1)

operations = [..., add, ...]

Should really the output of your program change depending on your internal implementation? That doesn't make much sense. Also, what happens to nameless functions?

Also, in another part of the program, you might want to show your functions as their types instead, etc., and then you'd have conflicting Show instances.

Generally, only implement Show when you know that there should be only one way of showing that thing, and that that way works for all values that need to be shown.


The simplest way of solving this problem would probably be to just store the name of the operation along with the operation. Like so:

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:


Another option:

data Operation = Add | Subtract | Multiply | Divide deriving (Show)

apply :: Operation -> Double -> Double -> Double
apply Add      = (+)
apply Subtract = (-)
apply Multiply = (*)
apply Divide   = (/)



回答3:


You cannot print the name of a function in Haskell (there may be some crazy tricks with meta programming but essentially you cannot). For your program it is probably easiest to define the list of operations as a list of pairs with a string of the name of each operator e.g.

let operations = [((+)," + "), ((-), " - ")), ((*), " * ")), ((/), " / ")]

You can get a list of just the operations by doing map fst operations and map snd operations to get their names.



来源:https://stackoverflow.com/questions/10962069/how-can-i-have-show-display-the-name-of-a-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!