如何解决具有单个构造函数的自引用数据类型不能为 `Show`n
data Chain = Link Int (Int -> Chain)
还有这个
ints :: Int -> Chain
ints n = Link (n+1) ints
我对这里到底发生了什么感到很困惑。这似乎是自身的无限递归,其中左侧的 ints
只是无休止地重复整个 ints
。书上说
[...] 我们可能会认为 ints
是一个很长的 ints
序列。我们从一个
通过应用第二个组件将此序列中的元素添加到下一个
ints n
到第一个。
> ints 0
* No instance for (Show Chain) arising from a use of `print'
: * In a stmt of an interactive GHCi command: print it
试图追上 deriving Show
不会成功
data Chain = Link Int (Int -> Chain) deriving Show
No instance for (Show (Int -> Chain))
arising from the second field of `Link' (type `Int -> Chain')
(maybe you haven't applied a function to enough arguments?)
Possible fix:
use a standalone 'deriving instance' declaration,so you can specify the instance context yourself
* When deriving the instance for (Show Chain)
不确定发生了什么或如何进行。任何类似的例子将不胜感激。
更新
这是 SML 代码
datatype chain = Link of (int * (int -> chain))
fun ints (n) = Link (n+1,ints)
> ints(0)
val it = Link (1,fn) : chain
不完全确定,但 fn
是匿名的 SML 方式,即 fn
是他们的 \
。这可能只是巧合。
那么,Haskell 无法处理 SML 的哪些方面呢?这是否与 Haskell 是纯粹的而 SML 不是有关?
解决方法
通常没有好的方法来Show
一个函数,所以当涉及到一个函数时,Haskell不会为你制作一个Show
的实例..
你可以自己写一个:
instance Show Chain where
show (Link n fn) = ...
但是现在您必须弄清楚如何显示fn:: Int->Chain
。在 Haskell 中,至少函数是原子的和不透明的。您无法拆开它们或检查它们的内容,只能应用它们。
这是怎么回事:
current :: Chain -> Int
current (Link i _) = i
next :: Chain -> Chain
next (Link i g) = g i
正如引述所说。你的 ints
是一个函数,所以这里没有无限的事情发生,只是函数应用程序延迟的可能性来获取链中的 next Link
所以下一个 {{1 }} 可以作为 its Int
元素找到。
关于印刷,
current
是一种可能的定义。关于该函数,我们无法提供任何信息,因此我们只能忽略它。
示例交互:
printLink :: Link -> String
printLink (Link i _) = "{Link of " ++ show i ++ " }"
等
接下来我们可以定义 ch1 = ints 0
i1 = current ch1 -- 1
ch2 = next ch1
i2 = current ch2 -- 2
以便 takeN :: Int -> Chain -> [Int]
从链 takeN 5 ch1
返回五个 Int
的列表,即 ch1
。
SML 是严格的,它不能像 Haskell 那样有无限列表。因此,SML 代表了一个函数的“下一个”计算,您必须显式调用该函数。
由于 Haskell 是懒惰的,我们也只是定义了 [1,2,3,4,5]
来将链转换为其中的无限条目列表,然后在其上使用标准函数 chainToList :: Chain -> [Int]
。
在您的新 SML 示例中,“take
”只是一个指示符,表明存在 a 函数,some 函数。在您的情况下,它是函数 fn
但运行时系统显然不知道这一点。这可能意味着 any 函数将在 SML 中打印为“ints
”,如您的示例所示。
但是你不需要打印它来使用它。
,这是在文本中没有足够远的阅读以及从一种语言 (SML) 而不是另一种语言获得误报的情况。事实证明,让 Chain
返回函数(如 ints
)直接输出是一种误用。这些 Chain
“生成器”只是作为另一个函数的中介来“查找”这样一个 Chain
对象中的位置,在 TLMLer 的示例中,数据的第二部分中的下一个整数构造函数。
data Chain = Link Int (Int -> Chain)
所以考虑另一个 Chain
生成器 fiveOrsevenInts
mod5or7 n = if (evenDiv n 5) then True else (evenDiv n 7)
where evenDiv a b = ((a `mod` b) == 0)
fiveOrsevenInts n = if (mod5or7 (n+1))
then (Link (n+1) fiveOrsevenInts)
else fiveOrsevenInts (n+1)
fiveOrsevenInts
基于可被 5 或 7 整除的数字创建一个 Chain
。据我所知,整个想法是“提前阅读”“链”。所以如果
fiveOrsevenInts (1) => Link 5 fiveOrsevenInts
诀窍是让 fiveOrsevenInts
(Int -> Chain
函数)作用于 5
以获取链中的下一个 Int
。而且正如我错误地认为的那样,我们根本不需要“看到”上述 fiveOrsevenInts (1)
的直接解析。
在链序列中获取所需位置的一般函数和像 fiveOrsevenInts
这样的链生成函数并返回该位置的成员是
chainItem n (Link i f) = if (n == 1)
then i
else chainItem (n-1) (f i)
现在,如果我想查看 5 或 7 的整数倍数序列中的第一个
chainItem 1 (fiveOrsevenInts 0)
5
chainItem 2 (fiveOrsevenInts 0)
7
chainItem 3 (fiveOrsevenInts 0)
10
...
chainItem 37 (fiveOrsevenInts 0)
119
fiveOrsevenInts 0
在哪里“播种”Chain
。在本章的后面,这个策略被应用于通过构建一个素数 Chain
生成器来查找素数序列。总而言之,我发现 The Little MLer 是一种学习其兄弟 Haskell 的有趣方式。当我完成时,我会尝试分享我的整体翻译。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。