只是一个简单的概念性问题,我目前正在努力学习和更好地理解Haskell。
我知道Show函数用于将值转换为字符串,但为什么函数类型不能与show一起使用?
Prelude> (\x -> x*3)
<interactive>:7:1:
No instance for (Show (a0 -> a0))
arising from a use of `print'
Possible fix: add an instance declaration for (Show (a0 -> a0))
In a stmt of an interactive GHCi command: print it
Prelude>
答案 0 :(得分:10)
并非他们不能,但通常没有充分的理由。
但如果你愿意,你绝对可以:
Prelude> :{
Prelude| instance Show (a -> b) where
Prelude| show _ = "A function."
Prelude| :}
Prelude> print (\x -> x + 7)
A function.
Prelude> print (\a b c -> a + b + c)
A function.
如果你想show
函数的文本表示,那么你就不能这样做。与Ruby,JS等元编程语言不同,Haskell对其内部的代码知之甚少。
答案 1 :(得分:8)
有一个部分解决方案超出了使用Data.Typeable的所有函数的固定字符串。
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Typeable
instance (Typeable a, Typeable b) => Show (a->b) where
show _ = show $ typeOf (undefined :: a -> b)
在ghci
> let test :: Int->Int; test x = x + x
> test
Int -> Int
不幸的是,没有类型签名,类型将默认为。
> let test x = x + x
> test
Integer -> Integer
此解决方案适用于多个功能元素,因为a -> b -> c
与a -> (b -> c)
相同,您可以将a -> d
写为d = b -> c
。
> let m10 a b c d e f g h i j = a * b * c * d * e * f * g * h* i * j
> m10
Integer -> Integer -> Integer -> Integer -> Integer -> Integer -> Integer
-> Integer -> Integer -> Integer -> Integer
但是,当不知道函数的参数是否具有可键入的类时,此方法不起作用,但map (+1)
将起作用map
则不会。
> map (+1)
[Integer] -> [Integer]
> map
<interactive>:233:1:
...
在看了Data.Data
的内部和一两个实验后,似乎可以重构为更广泛的覆盖更多功能。
答案 2 :(得分:3)
show
是在作为Show
类型类成员的函数上定义的函数(如果您不知道类型类是什么,它有点像OOP接口)。
默认情况下,函数不是类型类的成员,因此我们无法打印它们。
我们可以使用
使其成为类型类的成员instance Show (a -> b) where
show f = "Unicorns!!"
但是我们在这里意识到为什么它没有默认实现。没有一个简单明了的函数表示,而且haskell不想猜测,因此没有实例。
唯一的“允许”实例将是实际打印出函数的实例,但这需要实际的语言更改,即它将被硬连线到编译器中,这对于它的少数情况来说是不值得的。可能有用。
此外,它是一个非常重要的编译器更改,编译Haskell意味着f = g
和
f = g
完全迷失了。但你肯定希望在你的函数表示中。因此,你必须在整个程序中使用此字符串。这绝对不是你想要的二进制文件。
如果你真的想要它打印独角兽!!但是,请随意。