编译器耗尽内存,具有多态递归功能

时间:2016-05-26 07:47:03

标签: recursion elm

如果我尝试编译以下代码以添加到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

我想让第一个版本正常工作。这是编译器错误吗?是否有推荐的重构方法来避免这种情况?

1 个答案:

答案 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,您fLeftAddleft应用于Finger aa0a(fLeftAdd left a0) }}。 您还有right(fLeftAdd left a0)的结果具有相同类型的约束。

这意味着Finger a在给出Finger aa作为参数时应生成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上提出问题