-1

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 "\n";
  #       }
}

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?

Borodin
  • 126,100
  • 9
  • 70
  • 144
  • What is your question? Is your code producing an error; nothing; incorrect output? – Borodin Apr 26 '14 at 23:56
  • 3
    What do you imagine `split undef, $conclusion` does? You must *always* `use strict` and `use warnings` at the top of *every* Perl program, especially if you are asking for help with it – Borodin Apr 26 '14 at 23:59
  • I am using strick and warnings, this is just one small segment. – user3002620 Apr 27 '14 at 00:08
  • split undefined $conclusion splits conclusion on every character. the idea is that what i have in the file is the negated version of the conclusion(to be used with the proof method) but I want to be able to tell the user what the conclusion was, so i have to split up the string and either parse out, or put in a ~. – user3002620 Apr 27 '14 at 00:09
  • but that's not where the problem is. If you look closer, you'll see that I marked the spot where the error message was pointing to and indicated what it said aswell – user3002620 Apr 27 '14 at 00:10
  • You're right, it does. But the documentation doesn't say so. The first parameter to `split` should be a regex pattern, and using `//` will cause a split on every character. The only reason `undef` works is because it is evaluated as an empty string in this context, and you should be getting a warning that isn't appearing because you don't have warnings enabled. Or are you just ignoring the error messages and not telling us about them? – Borodin Apr 27 '14 at 00:19
  • I see the comment in your code now. Information like that belongs in the supporting text, not as a code comment. – Borodin Apr 27 '14 at 00:20
  • Are the numbers that you show really part of the data file? – Borodin Apr 27 '14 at 00:22
  • yeah sorry, its just, because the lines aren't numbered so putting that info in the text would make it really verbose to describe where the error occurred. Also, with the undef thing. I always use undef, never get an error. and the numbers are not part of the data file, no. – user3002620 Apr 27 '14 at 00:32
  • I know that split is doing its job because i tested it, theres also no trailing spaces or anything like that. The error I get is exactly as follows: can't use string ("a,b,c") as ARRAY ref while strict refs in use. – user3002620 Apr 27 '14 at 00:34
  • It may be doing what you want it to, but it is very poor coding practice. Most programmers familiar with Perl will be unsure about the effect it has, and if you had `use warnings` in place as you should then it would alert you to the problem – Borodin Apr 27 '14 at 00:59

2 Answers2

2

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, "\n";
  use Data::Dump;
  dd \@clauses;
}

output

a
[["a", "b", "c"], ["b", "~c"], ["~b"], ["~a"]]
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • Thanks for all your help Borodin, I swapped out my nested loops for your spit statement ad it seems to be working, that statement is really handy, i never though of that. gotta love perl 1 liners. – user3002620 Apr 27 '14 at 01:19
  • I have to ask you one more thing. its about the warnings thing. – user3002620 Apr 27 '14 at 01:20
  • I remember reading that use v5.14 was equivalent to use strict; use warnings; am i wrong? – user3002620 Apr 27 '14 at 01:20
  • `use v5.14` does just two things directly. It prevents the program from running on a Perl 5 interpreter older than version 14, and it enables the feature list associated with that version - the same as `use feature :5.14` which is `use feature qw/ switch say state unicode_strings /`. What you are referring to is a side-effect whereby Perl *itself* will enable `use strict` if the program requires a version of 5.11 or later. None of this has any effect on lexical warnings, which you must enable explicitly. – Borodin Apr 27 '14 at 01:36
  • I apologise if I seemed to be prevaricating over this question, but I would much rather lay the foundation for you to be able to fix your own code better, and for others to be able to read it better, rather than to simply provide a quick fix for one specific problem – Borodin Apr 27 '14 at 01:39
  • Since there are likely to be other people who are just as unclear about exactly what `use 5.14` *does*, it is batter in my opinion to explicitly `use strict` and `use warnings`. For the same reason I discourage similar modules like [`use Modern::Perl`](https://metacpan.org/pod/Modern::Perl). It is a useful programming principle in general to write what you *mean* instead of something else that happens to provide the same functionality – Borodin Apr 27 '14 at 01:43
1

The problem is that $clauses[$a] is a string, not an arrayref, so $clauses[$a][$b] = ... doesn't really make sense. (It means "set element $b of the array referred to by $clauses[$a] to ...", but $clauses[$a] doesn't refer to an array.)

To fix that, change this:

    my $str = $clauses[$a];
    my @tmp = split(',', $str);
    for (my $b = 0; $b < @tmp; $b++) {
      $clauses[$a][$b] = $tmp[$b]; # ERROR 
    }

to this:

    $clauses[$a] = [split /,/, $clauses[$a]];

so as to set $clauses[$a] to an arrayref with the contents you want.

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • thanks, its wierd because that works in another section of my code just fine, but ill have to go look it over again. – user3002620 Apr 27 '14 at 01:15