这个 Perl 脚本是一个粗糙的解决方案,对源文件结构做了一些假设。(例如:.hs
文件(而不是 .lhs
),签名在定义的前一行,定义紧贴左边缘等)
它试图处理(跳过)注释、方程式样式的定义(带有重复的左侧),以及在 ghci
中生成多行输出的类型。
毫无疑问,许多有趣的有效情况没有得到妥善处理。该脚本远未尊重 Haskell 的实际语法。
它非常慢,因为它为每个需要签名的函数启动一个 ghci
会话。
它创建一个备份文件 File.hs.bak
,将找到的函数和缺少签名的函数的签名打印到 stderr,并将升级后的源代码写入 File.hs
。它使用一个中间文件 File.hs.new
,并具有一些安全检查,以避免用垃圾覆盖您的内容。
请自行承担风险。
此脚本可能会格式化您的硬盘、烧毁您的房子、unsafePerformIO,并产生其他不纯的副作用。实际上,它很可能会这样做。
我感觉很肮脏。
在Mac OS X 10.6 Snow Leopard上进行了测试,使用了我的一些自己的.hs
源文件。
use warnings;
use strict;
my $sig=0;
my $file;
my %funcs_seen = ();
my %keywords = ();
for my $kw qw(type newtype data class) { $keywords{$kw} = 1;}
foreach $file (@ARGV)
{
if ($file =~ /\.lhs$/)
{
print STDERR "$file: .lhs is not supported. Skipping.";
next;
}
if ($file !~ /\.hs$/)
{
print STDERR "$file is not a .hs file. Skipping.";
next;
}
my $ghciPreTest = `echo 1 | ghci $file`;
if ($ghciPreTest !~ /Ok, modules loaded: /)
{
print STDERR $ghciPreTest;
print STDERR "$file is not valid Haskell source file. Skipping.";
next;
}
my $module = $file;
$module =~ s/\.hs$//;
my $backup = "$file.bak";
my $new = "$module.New.hs";
-e $backup and die "Backup $backup file exists. Refusing to overwrite. Quitting";
open OLD, $file;
open NEW, ">$new";
print STDERR "Functions in $file:\n";
my $block_comment = 0;
while (<OLD>)
{
my $original_line = $_;
my $line = $_;
my $skip = 0;
$line =~ s/--.*//;
if ($line =~ /{-/) { $block_comment = 1;}
$line =~ s/{-.*//;
if ($block_comment and $line =~ /-}/) { $block_comment=0; $skip=1}
if ($line =~ /^ *$/) { $skip=1; }
if ($block_comment) { $skip = 1};
if (!$skip)
{
if (/^(('|\w)+)( +(('|\w)+))* *=/ )
{
my $object = $1;
if ((! $keywords{$object}) and !($funcs_seen{$object}))
{
$funcs_seen{$object} = 1;
print STDERR "$object\n";
my $dec=`echo ":t $1" | ghci $file | grep -A100 "^[^>]*$module>" | grep -v "Leaving GHCi\." | sed -e "s/^[^>]*$module> //"`;
unless ($sig)
{
print NEW $dec;
print STDERR $dec;
}
}
}
$sig = /^(('|\w)+) *::/;
}
print NEW $original_line;
}
close OLD;
close NEW;
my $ghciPostTest = `echo 1 | ghci $new`;
if ($ghciPostTest !~ /Ok, modules loaded: /)
{
print $ghciPostTest;
print STDERR "$new is not valid Haskell source file. Will not replace original (but you might find it useful)";
next;
} else {
rename ($file, $backup) or die "Could not make backup of $file -> $backup";
rename ($new, $file) or die "Could not make new file $new";
}
}
hs-lint-replace-without-ask
设置为t
,Emacs中的hs-lint
命令将自动应用建议。我不确定如何将其限制为仅适用于类型签名,但肯定有一种方法。我之所以只是发布评论,是因为这不是EclipseFP解决方案。 - Jon Purdy