具有单个构造函数的自引用数据类型不能为“Show”n
Self-referential data type with single constructor cannot be `Show`n
这是来自The Little MLer。我有 this
data Chain = Link Int (Int -> Chain)
还有这个
ints :: Int -> Chain
ints n = Link (n+1) ints
我对这里到底发生了什么感到很困惑。这似乎是一个无休止的递归本身,其中左侧的 ints
只是无休止地重复整个 ints
。书上说
[...] we may think of ints
as a very long sequence of ints
. We go from one
element in this sequence to the next by applying the second component
of ints n
to the first.
我不确定它是如何做到的。但是这会产生一个错误
> 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
是他们的 \
。这可能只是巧合。
那么 SML 有什么 Haskell 无法处理的?这与 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
所以下一个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
returns 来自链ch1
的五个Int
的列表,即[1,2,3,4,5]
.
SML 是严格的,它不能像 Haskell 那样有无限的列表。因此,SML 表示函数的“下一个”计算,你 必须显式调用该函数。
由于 Haskell 是惰性的,我们也只是定义 chainToList :: Chain -> [Int]
将链转换为其中的无限条目列表,然后在其上使用标准函数 take
.
在您的新 SML 示例中,“fn
”只是一个指示器,表明那里有 a 函数,some 函数.在你的情况下,它是函数 ints
但 运行-time 系统显然不知道。这可能意味着 any 函数将在 SML 中打印为“fn
”,如您的示例所示。
但您无需打印即可使用。
这是一个没有在文本中阅读足够远的情况,以及从一种语言 (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 的有趣方式。当我完成后,我会尝试分享我的整体翻译。
这是来自The Little MLer。我有 this
data Chain = Link Int (Int -> Chain)
还有这个
ints :: Int -> Chain
ints n = Link (n+1) ints
我对这里到底发生了什么感到很困惑。这似乎是一个无休止的递归本身,其中左侧的 ints
只是无休止地重复整个 ints
。书上说
[...] we may think of
ints
as a very long sequence ofints
. We go from one element in this sequence to the next by applying the second component ofints n
to the first.
我不确定它是如何做到的。但是这会产生一个错误
> 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
是他们的 \
。这可能只是巧合。
那么 SML 有什么 Haskell 无法处理的?这与 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
所以下一个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
returns 来自链ch1
的五个Int
的列表,即[1,2,3,4,5]
.
SML 是严格的,它不能像 Haskell 那样有无限的列表。因此,SML 表示函数的“下一个”计算,你 必须显式调用该函数。
由于 Haskell 是惰性的,我们也只是定义 chainToList :: Chain -> [Int]
将链转换为其中的无限条目列表,然后在其上使用标准函数 take
.
在您的新 SML 示例中,“fn
”只是一个指示器,表明那里有 a 函数,some 函数.在你的情况下,它是函数 ints
但 运行-time 系统显然不知道。这可能意味着 any 函数将在 SML 中打印为“fn
”,如您的示例所示。
但您无需打印即可使用。
这是一个没有在文本中阅读足够远的情况,以及从一种语言 (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 的有趣方式。当我完成后,我会尝试分享我的整体翻译。