Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
148 views
in Technique[技术] by (71.8m points)

perl - Can't use string ("a,b,c") as an ARRAY ref

I am writing some code for an automated theorem prover. I wanted to implement an option for the user to pass a file on the cmd line and have it operate in batch mode.

Here is the code to parse the file and fill the @clauses array.

# batch mode
if ($ARGV[0]) {

  my $filename = $ARGV[0];

  open(IN, "<", $filename);
  chomp(@clauses = <IN>);
  $conclusion2 = $clauses[@clauses - 1];

  # set sos as negated conclusion
  $SOS[0][0] = $conclusion2;

  # negate the negation to get the desired conclusion for later
  @conclusion = split(undef, $conclusion2);

  # look for a ~, remove it if you find it, add one if you don't
  for (my $i = 0 ; $i < @conclusion ; $i++) {

    # while you're at it.....
    # get rid of spaces and anything that isn't a ~ or letter
    $conclusion[$i] =~ s/( |[^A-Za-z~])//;
    if ($conclusion[$i] eq '~') {
      splice(@conclusion, $i, 1);
      $i--;
      $found = 1;
    }
  }

  if (!$found) {
    $conclusion = "~$conclusion2";
  }
  else {
    $conclusion = join(undef, @conclusion);
  }

  # now break up each line and make @clauses 2d
  for (my $a = 0 ; $a < @clauses ; $a++) {
    my $str = $clauses[$a];
    my @tmp = split(',', $str);
    for (my $b = 0; $b < @tmp; $b++) {
      $clauses[$a][$b] = $tmp[$b];       # ERROR HERE
    }
  }

  #       for(my $i=0; $i<@clauses;$i++)
  #       {
  #               print "$i";
  #               for(my $b=0; $b<=@{@clauses};$b++)
  #               {
  #                       print "$clauses[$a][$b]";
  #               }
  #               print "
";
  #       }
}

I'm putting in more than I really need to, but the troublesome part is when I'm trying to break up the lines of the file by the commas and make the array two-dimensional.

At the line I have marked I get the error

Can't use string ("a,b,c") as an ARRAY ref while "strict refs" in use

The input file is set up like this

a,b,c
b,~c
~b
~a

This would be a proof to prove that a must be true

It's weird, because in the code for the interactive section, I do the exact same thing, almost verbatim and it works perfectly.

EDIT I'm certain that somehow, the error lies within this line

$clauses[$a][$b] = $tmp[$b];

the error message is as follows:

can't use string ("a,b,c") as ARRAY ref while strict refs in use.

I don't see the need for any dereferencing on my part so what could the problem be?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You should really show as much of your program as possible, as it is hard to see the scope of the variables that you don't declare.

I can assure you that, if you have use warnings in place as you should, then split undef will cause the warning

Use of uninitialized value in regexp compilation

The problem is that you have set

$clauses[$a] = "a,b,c";
@tmp = ('a', 'b', 'c');

You then try to do

$clauses[$a][$b] = $tmp[$b] for 0 .. 2

but $clauses[$a] is a string, not an array reference. It is the same as writing

"a,b,c"[$b] = $tmp[$b] for 0 .. 2

which makes no sense. Hence the error message Can't use string ("a,b,c") as an ARRAY ref.

A trivial fix would be to write

$clauses[$a] = undef;

immediately after

my $str= $clauses[$a]

so that the array element is now undefined, and Perl can autovivify an anonymous array here when the elements are copied.

However your code could use a little more work, so here is a version that does what I think you want. I have dumped the values of @clauses and $conclusion at the end to show their contents

use strict;
use warnings;

my $conclusion;
my $conclusion2;
my @SOS;

if (@ARGV) {

  my ($filename) = @ARGV;

  open my $in_fh, '<', $filename or die qq{Unable to open "$filename" for input: $!};
  chomp(my @clauses = <DATA>);
  close $in_fh;

  $conclusion2 = $clauses[-1];
  $SOS[0][0] = $conclusion2;

  $conclusion = $conclusion2;
  $conclusion =~ tr/A-Za-z~//cd;
  $conclusion = '~'.$conclusion unless $conclusion =~ tr/~//d;

  $_ = [ split /,/ ] for @clauses;

  print $conclusion, "
";
  use Data::Dump;
  dd @clauses;
}

output

a
[["a", "b", "c"], ["b", "~c"], ["~b"], ["~a"]]

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...