簡體   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