只是一个快速的概念性问题,我目前正试图更好地学习和理解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>
不是他们不能,而是通常没有一个好的理由。
但如果你愿意,你绝对可以:
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代码对自己的内部结构知之甚少。
对于使用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)
相同,您可以将d = b -> c
写成a -> d
。
> 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
的内部结构和一两个实验之后,它似乎可以被重构得更一般化一些,覆盖更多的函数。
show
是定义在Show
类型类成员函数上的函数(如果你不知道类型类是什么,它有点像OOP接口)。
默认情况下,函数不是类型类的成员,因此不能打印它们。
可以用
使它成为类型类的成员instance Show (a -> b) where
show f = "Unicorns!!"
,但这里我们意识到为什么它不是默认实现的。没有一个简单、明显的函数表示,haskell不想猜测,因此没有实例。
唯一"允许的"实例将是实际打印出函数的实例,但这将需要实际的语言更改,即它将被硬连接到编译器中,这对于少数可能有用的情况来说是不值得的。
更进一步,这是一个重要的编译器变化,Haskell被编译了这意味着f = g
和
f = g
完全丢失了。但你肯定想在函数表示中看到它。因此,您必须在整个程序中拖着这个字符串。这绝对不是你想要的二进制文件。
如果你真的想让它打印独角兽!!不过,请随意。