如果我尝试编译以下代码以添加到fingertree,则elm编译器会等待很长时间,然后报告它内存不足。
<select onchange="jumpmenu('parent',this)">
<option value="<?php echo TRoute::_("index.php?option=com_adsmanager&view=result&new_search=1&catid=".$this->catid); ?>">Please Select a Location</option>
<?php
$ad_location = JRequest::getVar('ad_location');
$fieldmodel = $this->getModel("field");
$field_values = $fieldmodel->getFieldValues();
foreach($field_values[17] as $fields){ //print_r($fields); ?>
<option value="<?php echo TRoute::_("index.php?option=com_adsmanager&view=result&new_search=1&catid=".$this->catid."&ad_location=".$fields->fieldvalue); ?>" <?php if ($fields->fieldvalue == $ad_location) echo 'selected="selected"'; ?> ><?php echo $fields->fieldtitle; ?></option>
<?php }?>
</select>
我的第一个想法是,也许你不能进行多态递归(一个多态函数用不同的类型签名调用自己)。然而,这个变体,用列表替换自定义“手指”和“节点”类型,编译很好:
module FingerTree exposing(..)
type Node a
= Node2 a a
| Node3 a a a
type Finger a
= One a
| Two a a
| Three a a a
| Four a a a a
type FingerTree a
=Empty
|Single a
|Deep (Finger a) (FingerTree(Node a)) (Finger a)
fLeftAdd: a -> Finger a -> Finger a
fLeftAdd a0 finger =
case finger of
One a1 -> Two a0 a1
Two a1 a2 -> Three a0 a1 a2
Three a1 a2 a3 -> Four a0 a1 a2 a3
Four a1 a2 a3 a4 -> finger
leftAdd: a -> FingerTree a -> FingerTree a
leftAdd a0 fingerTree=
case fingerTree of
Empty -> Single a0
Single a1 -> Deep (One a0) Empty (One a1)
Deep left middle right ->
case left of
Four a1 a2 a3 a4 ->
Deep(Two a0 a1) ( leftAdd (Node3 a2 a3 a4) middle) right
_ -> Deep (fLeftAdd left a0) middle right
我想让第一个版本正常工作。这是编译器错误吗?是否有推荐的重构方法来避免这种情况?
答案 0 :(得分:3)
您确定最后一行是_ -> Deep (fLeftAdd left a0) middle right
而不是_ -> Deep (fLeftAdd a0 left) middle right
吗?如果我改变它,一切都很好。
请注意fLeftAdd
的签名为fLeftAdd: a -> Finger a -> Finger a
。您是FingerTree a
上的模式匹配,特别是Deep (Finger a) (FingerTree(Node a)) (Finger a)
案例。
使用_ -> Deep (fLeftAdd left a0) middle right
,您fLeftAdd
将left
应用于Finger a
,a0
和a
,(fLeftAdd left a0)
}}。
您还有right
和(fLeftAdd left a0)
的结果具有相同类型的约束。
这意味着Finger a
在给出Finger a
和a
作为参数时应生成fLeftAdd: a -> Finger a -> Finger a
,这会打破自leftAdd: a -> FingerTree a -> FingerTree a
leftAdd a0 fingerTree=
case fingerTree of
Deep left middle right ->
Deep (fLeftAdd left a0) middle right
_ -> Single a0
以来的类型推断。
这是编译器不会耗尽内存的最小示例:
leftAdd
我将其粘贴到Try Elm中,并收到以下错误消息:
- TYPE MISMATCH ------------------------------------------- --------------------
a -> FingerTree a -> FingerTree a
的类型注释与其定义不匹配。27 | leftAdd:a - &gt; FingerTree a - &gt; FingerTree a ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^类型注释说:
Finger ? -> FingerTree ? -> FingerTree (Finger ?)
但我推断定义有这种类型:
left
提示:类型注释过于通用。你可以切换 到我推断的类型。这些问题可能很微妙,所以请阅读 更多关于它。 https://github.com/elm-lang/elm-compiler/blob/0.17.0/hints/type-annotations.md
- INFINITE TYPE ------------------------------------------- --------------------
我推断
的一种奇怪的自引用类型?
30 |左中右上 - &gt; ^^^^这是我写下这个类型的最大努力。你会看见 ?和∞表示已经重复某事的类型的部分 无限地打印出来。
Expression<Func<>>
在这些情况下,通常盯着这种类型并不是那么有用,所以 绝对阅读有关如何计算这个想法的调试提示 出: https://github.com/elm-lang/elm-compiler/blob/0.17.0/hints/infinite-type.md
我建议您尝试创建simple self contained compilable example并在compiler project上提出问题