2012-06-09 87 views
3

作爲一個讓我熟悉Haskell的簡單練習,在Youtube上徘徊並陷入美國倒計時遊戲節目後,我想爲Numbers遊戲做一個解算器。如何顯示功能的名稱?

您會得到6個數字,需要將它們與(+) (-) (*) (/)結合才能獲得給定的結果。

enter image description here

到目前爲止,我已經得到了什麼是很腦殘,

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

...但明顯顯示不知道該怎麼辦的功能。

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

我該如何解決這個問題?我是否需要混淆類型和數據構造函數來創建我自己的可以打印的函數,還是有一些更簡單的方法呢?

+4

'濾波器(\ q - > Q/=一個&& Q/= B && Q/= C && Q/= d)'可以寫成作爲'過濾器(\'notElem \'[a,b,c,d])' – sdcvvc

+0

@sdcvvc這是我以前沒有意識到的反引號的用法。 – badp

+0

作爲教學材料,你可以檢查這個視頻[博士Graham Hutton - 函數式編程基礎 - 倒計時問題](http://channel9.msdn。com/shows/Going + Deep/C9-Lectures-Dr-Graham-Hutton-Functional-Programming-Fundamentals-Chapter-11-of-13) – jedf

回答

8

我通常不會建議你爲函數實現一個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]) 
1

你不能在Haskell中打印一個函數的名字(可能有一些瘋狂的元編程技巧,但基本上你不能)。對於你的程序來說,將操作列表定義爲包含每個操作符的名稱字符串的對列表可能是最簡單的,例如,

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

您可以通過執行map fst operationsmap snd operations得到他們的名字得到的只是在操作的列表。

13

另一種選擇:

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

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