繁体   English   中英

自动检测一个Haskell function是否为尾递归

[英]Automatically detect whether a Haskell function is tail recursive

我目前正在为 Haskell 课程编写自动评分器。 对于“尾递归”部分,我需要一种方法来自动安全地检测给定的 Haskell function 是否为尾递归。

我搜索了现有工具,但找不到任何东西。 我假设必须有一种方法可以自动执行此操作,因为毕竟这是 Haskell 编译器为我们所做的。 该方法不必使用特定语言或任何东西,因为评分者是项目中的外部实体。 例如,它可以是 Haskell 库、命令行工具或用任何其他语言编写的代码(C、Java、Python 等)。

如果实际上没有任何这样的工具,我想我将不得不为 Haskell 使用类似词法分析器的东西,并自己编写检测尾递归的自定义代码。

我首先要指出,尾递归在 Haskell 中很少是优点。如果您想使用 Haskell 作为教授尾递归的媒介,这很好,但实际上在 Haskell 中编写尾递归函数通常会被误导。

假设你仍然想这样做,我会强调

毕竟这就是 Haskell 编译器为我们所做的

确实是的。 那么为什么会存在除编译器以外的任何工具呢? 编译器已经做到了这一点。 所以,当你想这样做时, 使用编译器 我相信这不会是微不足道的,因为你必须学习编译器的类型和其他 API 但它实际上是正确的。

我会首先查看 function 之类的isAlwaysTailCalled ,看看它是否符合您的要求。 如果没有,也许您需要使用 function 定义的 AST。

我基本上同意 amalloy,但是对于这个自动评分器(大概应该只是清除明显错误的快速方法,而不是一个完整可靠的认证工具),我会在模板 Haskell 中拼凑一些东西。

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE LambdaCase      #-}

module TailRecCheck where

import Language.Haskell.TH

isTailRecursive :: Dec -> Bool
isTailRecursive (FunD fName clauses) = all isClauseTR clauses
 where 
       isClauseTR (Clause _ (NormalB (AppE f x)) _)
          -- Function application that could be a tail call
          = case f of
             -- It's only a tail call if the function is the
             -- one we're currently defining, and if the rest
             -- is not recursive
             VarE fn -> fn==fName && isConstant x
       -- Constant expressions are allowed as base cases
       isClauseTR (Clause _ (NormalB body) _) = isConstant body
       --isClauseTR _ ... _ = ...

       isConstant (VarE n) = n /= fName
       isConstant (ConE _) = True
       isConstant (LitE _) = True
       isConstant (AppE f x) = isConstant f && isConstant x
       isConstant (InfixE l op r)
          = all isConstant l && isConstant op && all isConstant r
       --isConstant ... = ...

assertTailRecursiveDefs :: Q [Dec] -> Q [Dec]
assertTailRecursiveDefs n = n >>= mapM`id`\case
   dec
     | isTailRecursive dec -> return dec
     | otherwise -> fail ("Function "++showName dec
                              ++" is not tail recursive.")
 where showName (FunD n _) = show n

像这样使用

{-# LANGUAGE TemplateHaskell #-}

module TailRecCheckExample where

import TailRecCheck

assertTailRecursiveDefs [d|
    f x = 4

    g 0 = 1
    g x = g (x-1)

    h 0 = 1
    h x = 1 + h (x-1)
  |]
TailRecCheckExample.hs:7:1: error:
    Function h_6989586621679042356 is not tail recursive.
  |
7 | assertTailRecursiveDefs [d|
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM