2011年10月26日 星期三

Perl 使用constant注意不能expand常數

As with all use directives, defining a constant happens at compile time. Thus, it's probably not correct to put a constant declaration inside of a conditional statement (like if ($foo) { use constant ... } ).
Constants defined using this module cannot be interpolated into strings like variables. However, concatenation works just fine:
  1. print "Pi equals PI...\n"; # WRONG: does not expand "PI"
  2. print "Pi equals ".PI."...\n"; # right

Perl 中文教學 (朝陽科技大學)


 Perl 教學: 啟始


這是Nik Silver於School of Computer StudiesUniversity of Leeds教授Perl程式的內容,原始設計為一天的教學實習內容。 我將其翻譯並作小幅的修改使內容能符合朝陽科技大學學生個人網頁設計的目的。
教學內容架構如下:

2011年10月21日 星期五

PERL :$\控制output輸出加於行尾的文字; $/控制input輸入結束判斷符號

{


local $/ = undef;
#平常輸入Enter就將input資料結束,若設定成undef則可以進行多行輸入
open FH,"testfile.txt";
while(<FH>){
  print $_."[END]";#將資料讀成一行,穿吃給第一個iteration的$_
}
close FH;
}

#輸出結果:
hello world 
I am stayhigh 
Want Be an Hacker in Perl 

line break

here end
[END]

Perl open file ,filehandle technique


while ($line = <CHECKBOOK>) {
  print $line;
}

Opening files

Opening a file in perl in straightforward:open FILE, "filename.txt" or die $!;The command above will associate the FILE filehandle with the file filename.txt. You can use the filehandle to read from the file. If the file doesn't exist - or you cannot read it for any other reason - then the script will die with the appropriate error message stored in the $! variable.
What if you wanted to modify the file instead of just reading from it? Then you'd have to specify the appropriate mode using the three-argument form of open.
open FILEHANDLE, MODE, EXPRThe available modes are the following:
modeoperandcreatetruncate
read<
write>
append>>

Each of the above modes can also be prefixed with the + character to allow for simultaneous reading and writing.
modeoperandcreatetruncate
read/write+<
read/write+>
read/append+>>

Callability of procedures


A more useful concept is the converse of the static scope of the name of a procedure, which we refer to as the callability of the procedure. Callability of a procedure determines the procedures that it can call.


#NOTE:此處說明Pascal的函數呼叫是否可行
Algorithm to draw the static tree of a Pascal program:
1.  Draw the main() program as the root node of the tree.
2.  Identify all the procedures/functions directly defined in main()Draw them as child nodes of main() node.
3.  Repeatedly carry out step 2 for all the leaf nodes of the tree, until there are no more nested procedures in the program.
In the Pascal program presented earlier, the procedures read()compute() and print() are defined directly inmain(), and are its children. The procedure prompt() is defined within read(), and is its child. The procedures initialize() and transform() are defined within compute()and are its children. The procedure defaults() is defined within initialize(), and is its child. The static tree of the program is shown below.


清楚講解 變數scope的網站

http://phobos.ramapo.edu/~amruth/grants/problets/courseware/scope/



static ancestors,static parents
static non-local referencing environment :
of a procedure p() is the set of all the unique variables declared in the static ancestors of p(), that have not been re-declared in the procedure p().


dynamic ancestors
The dynamic non-local referencing environment :
of a procedure p() is the set of all the unique variables declared in the dynamic ancestors of p(), that have not been re-declared in the procedure p().

Perl:Lexical Scoping 與 Dynamic Scoping 觀念比較



Lexical (Static) Scoping :從block 中找變數 從內層找到外層(my operator)

Dynamic Scoping:由函數呼叫順序逆序將變數找出來(local operator)

先前我們提到 shadow 的觀念; 這節我們要談的是 shadow 沒有發生的狀況: 在程式原始碼的某一點 (例如在副程式 h 當中), 用到一個變數 x, 但 local variables 當中並沒有 x。 先前我們的答案很簡單: 那麼這個 x 指的當然就是 global 的 x 嘍!
問題是: 那一個 global 的 x? 在 pascal 與 lisp 語系 等等允許副程式定義裡面又有其他副程式定義的語言裡, 單單講 global 與 local 並不清楚。 如果最內層的副程式裡面沒有宣告 x 但卻用到了 x, 那麼究竟要去那裡找其他 (比較 global) 的 x? 像這個 例子
最直覺的答案是: 看程式碼, 找最內層 (最 local) 的 x。 這種「根據程式碼當中, 變數出現的位置, 來決定未在本地宣告的變數究竟來自何處」的規則, 叫做 lexical scoping 也叫做 static scoping。 大部分的語言 (例如 pascal) 都採取這個規則。
還可能有別種規則嗎? Lisp 語系的眾多方言 (dialects) 當中, 有許多 (例如 emacs lisp) 採取的是 dynamic scoping: 光看程式碼還不夠, 必須真的知道程式執行的過程, 畫出程式執行到使用 x 那句話當時的 系統堆疊, 由內 (最近放上去的 A.V.) 向外找到何處有宣告 x。 在 lisp 的某些方言 (例如 librep) 當中, 平常採取的是 lexical scoping; 但如果你用 defvar 宣告變數, 則這個名稱的變數就變成了 dynamic scoping。 在 perl 當中, 比較常用 lexical 變數 (用 my 宣告); 如果要用 dynamic scoping, 必須用 use vars 宣告全域變數, 用 local 宣告局部變數。
用術語來講, lexical scoping 循的是 static ancestors 的族譜向上找 (h -> f -> 最外層); 而 dynamic scoping 循的是 dynamic ancestors 的族譜向上找 (h -> g1 -> f -> 最外層 或 h -> g2 -> f -> 最外層)。

深入了解local標籤的意義

$x = 10;
first();
sub first {
    local ($x) = "zen";      # $x is still global, and has a new value
    print "in first:",$x,"\n";#print "zen"
    second();
}


sub second {
    print "in second:",$x,"\n";   # Prints "zen", the current value of the global $x
}


print $x,"\n";#Prints 10
#NOTE:In other words, local makes a global variable's new value temporary;

dynamically allocated scalars

What about dynamically allocated scalars ? It turns out that Perl doesn't have any notation for doing
something like this, presumably because you almost never need it. If you really do, you can use the
following trick: Create a reference to an existing variable, and then let the variable pass out of scope.
{
    my $a = "hello world";  # 1
    $ra = \$a;              # 2 
}
print "$$ra \n";            # 3
The my operator tags a variable as private (or localizes it, in Perl-speak). You can use the local operator
instead, but there is a subtle yet very important difference between the two that we will clarify in Chapter
3. For this example, both work equally well.
Now, $ra is a global variable that refers to the local variable $a (not the keyword local). Normally, $a
would be deleted at the end of the block, but since $ra continues to refer to it, the memory allocated for $a
is not thrown away. Of course, if you reassign $ra to some other value, this space is deallocated before $ra
is prepared to accept the new value.
You can create references to constant scalars like this:
$r = \10;  $rs = \"hello";
Constants are statically allocated and anonymous.
A reference variable does not care to know or remember whether it points to an anonymous value or to an
existing variable's value. This is identical to the way pointers behave in C.

雜湊初始化:具名雜湊用( ) ;匿名雜湊用{ }

# An ordinary hash uses the prefix and is initialized with a list
# within parentheses
%hash = ("flock" => "birds", "pride" => "lions");#()


# An anonymous hash is a list contained within curly braces. 
# The result of the expression is a scalar reference to that hash.
$rhash = {"flock" => "birds", "pride" => "lions"};#{}

用Perl裡的 use Benchmark;

use Benchmark;#引入Benchmark






sub approved{
  my $line = <testfile.txt>;
  exit(0) unless defined($line);
  return \$line;
}


timethis(100,"approved");#算出call函數名為approved呼叫100次所耗費的時間

Arrow Notation 需知 $rarray->[0,2]等同於 $rarray->[2] 啦!





Caution: This notation works only for single indices, not for slices. Consider the following:
print $rarray->[0,2]; # Warning: This is NOT an indirect array slice.


@array = (1..10);
$rarray = \@array;
print $rarray->[0,2];#等同於print $rarray -> [2];


(切記: enumerated or comma-separated list 
總是 returns 最後一個元素在實數語境中 in a scalar context.)




Perl treats the stuff within the brackets as a comma-separated expression that yields the last term in the
array: 2. Hence, this expression is equivalent to $rarray->[2], which is an index lookup, not a slice.


(Recall the rule mentioned earlier: An enumerated or comma-separated list always returns the last
element in a scalar context.)

用Arrow Notation 製作 shortcut

#arrowNotation.pl




@array = (1..10);
$rarray = \@array;
print $rarray->[1],"\n" ;    # The "visually clean" way
#instead of the approaches we have seen earlier:
print $$rarray[1],"\n";      # Noisy, and have to think about precedenceprint ${$rarray}[1];    # The way to get tendinitis!


#輸出結果:
2
2

$$rarray[1]的結合順序? 其實就是 ${$rarray}[1]啦!

Confusion About Precedence
The expressions involving key lookups might cause some confusion. Do you read $$rarray[1] as
${$rarray[1]} or {$$rarray}[1] or ${$rarray}[1]?
(Pause here to give your eyes time to refocus!)
As it happens, the last one is the correct answer. Perl follows these two simple rules while parsing such
expressions: (1) Key or index lookups are done at the end, and (2) the prefix closest to a variable name
binds most closely. When Perl sees something like $$rarray[1] or $$rhash{"browns"}, it leaves index
lookups ([1] and {"browns"}) to the very end. That leaves $$rarray and $$rhash. It gives preference to
the `$' closest to the variable name. So the precedence works out like this: ${$rarray} and ${$rhash}.
Another way of visualizing the second rule is that the preference is given to the symbols from right to left
(the variable is always to the right of a series of symbols).
Note that we are not really talking about operator precedence, since $, @ , and % are not operators; the
rules above indicate the way an expression is parsed.

Advance technique : hash slice

#hashSlice.pl


%hash =(
  k1 => "v1",
  k2 => "v2",
  k3 => "v3",
  k4 => "v4",
  
);


$rhash =\%hash;
print "@$rhash{k1,k3}"; #hash slice implementation ,print out ->"v1 v3"
@sliceResult = @$rhash{k1,k3};
print @sliceResult; #Display:v1v3

2011年10月20日 星期四

利用state 宣告變數使變數可以存入值的狀態

NOTE:記得use v5.010才能使用state敘述




#state.pl



use v5.010;
sub function{
    state $var= 0;
    $var++;
    print "Now \$var state is :",$var,"\n";
}


&function
&function
&function



#輸出結果:

hello $n now is :1
hello $n now is :2
hello $n now is :3
_______________________________________

#state.pl



use v5.010;
sub function{
    my $var= 0;
    $var++;
    print "Now \$var state is :",$var,"\n";
}


&function
&function
&function



#輸出結果:

hello $n now is :1
hello $n now is :1
hello $n now is :1


  • state EXPR
  • state TYPE EXPR
  • state EXPR : ATTRS
  • state TYPE EXPR : ATTRS
    state declares a lexically scoped variable, just like my does. However, those variables will never be reinitialized, contrary to lexical variables that are reinitialized each time their enclosing block is entered.
    state variables are enabled only when the use feature "state" pragma is in effect. See feature.



2011年10月19日 星期三

perlvar: my ,our

our is global
my is lexical


we use 'package to declare them.
'main' is the default namespace 
globals are package variables
variables relating to that namespace
(not the same as superglobals)


our $name ; # $main::name
package My::Package;
our $name;#$My::Package::name
say $Moose::VERSION;




What is a lexical variable?
Scoped variables
Variables that exist only in a scope!
Available scopes:block, file ,eval
We defind lexical variables with 'my'
(they are saved in a lex pad)




Lexical variable , examples:
{my $exists_only_here}
{my $outer;{my $inner;}}
foreach my $name(@names){
    say $name;
}
say $name; #ERROR




Lexical variables,quiz:
package Example;
my $exvar =30;
package main;
print $exvar;#Display output 30


Answer:
NO ERROR!
my is lexical
package is a namespace, not a scope 
The scope here is the "file scope"
Here is the correct way to do it:
{package Example;my $exvar;}


What is a state variable?
Lexical variables with a twist!
The don't get reinitialized
sub inc{
    state $myvar =0;#default value
    return ++$myvar;
}









#pushonlyonrealarray.pl
#use strict;


push @{$result},"one";
print "\$result :",$result,"\n";


print "\@\$result:",@$result,"\n";


@arr =(1..10);
$ref = \@arr;
print "get array data by ref :",@$ref;


#輸出結果:

$result :ARRAY(0x10463af0)
@$result:one
get array data by ref :12345678910



If you wanted just to append to a row, you'd have to do something a bit funnier looking:

    # add new columns to an existing row
    push @{ $LoL[0] }, "wilma", "betty";
Notice that I couldn't say just:

    push $LoL[0], "wilma", "betty";  # WRONG!
In fact, that wouldn't even compile. How come? 
Because the argument to push() must be a real array, not just a reference to such.



he argument to push() must be a real array, not just a reference to such.

if you wanted just to append to a row, you'd have to do something a bit funnier looking:

# add new columns to an existing row
    push @{ $LoL[0] }, "wilma", "betty";
Notice that I couldn't say just:

push $LoL[0], "wilma", "betty";  # WRONG!
In fact, that wouldn't even compile. How come? Because the argument to push() must be a real array, not just a reference to such.

Perl:進階二維陣列操作

sub func2{
    #print "func2 ,para:$_[0]\n";
    return "[RETURN]$_[0]";
}
my @LoL=();


#initialization  [NOTE]:沒有作initialization就直接運算容易導致問題發生
for $x (3,7,9){
    $LoL[$x][20]="initStr";
    }
    
#print out
for $x(3,7,9){
    print $LoL[$x][20],"\n";
    }


#operation on them
for $x ( 3, 7, 9 ) {


        #print "testOp >>   ",$LoL[3][20]+= func2(3),"\n" ;
        $LoL[$x][20] =$LoL[$x][20].func2($x);
        print "\n";
    }
#print out result
for $x(3,7,9){
    print $LoL[$x][20],"\n";
    }




#輸出結果:

initStr
initStr
initStr






initStr[RETURN]3
initStr[RETURN]7
initStr[RETURN]9

Perl:二維陣列的Assignment

#mutiAssign.pl
sub func{
    print "func invoked....$_[0],$_[1]\n";
    return "Hello".scalar($_[0]).scalar($_[1]);
}




for $x (1 .. 3) {
        for $y (1 .. 3) {
            print "(",$x,",",$y,"):";
            $LoL[$x][$y] = func($x, $y);
#all element of  two dims @LoL NOTE:get the return value of'func'!
            print "\n";
        }
    }
    
for $ele(@LoL){
    print $ele,"\n";#印出陣列的記憶體位置
    print @$ele,"\n";#印出陣列中全部的元素值


}




#輸出結果:

(1,1):func invoked....1,1


(1,2):func invoked....1,2


(1,3):func invoked....1,3


(2,1):func invoked....2,1


(2,2):func invoked....2,2


(2,3):func invoked....2,3


(3,1):func invoked....3,1


(3,2):func invoked....3,2


(3,3):func invoked....3,3






ARRAY(0x104a1440)
Hello11Hello12Hello13
ARRAY(0x104a1938)
Hello21Hello22Hello23
ARRAY(0x104a19b0)
Hello31Hello32Hello33

Perl:A reference to reference


#aReftoRef.pl


@arr= (1..10);
$ref = \@arr;
print $ref,"\n";            #ARRAY(0x104a14a0)
$another_ref = \$ref;
$another_ref2 = \$ref;


#Note:get the same address of ref!
print $another_ref,"\n";    #REF(0x104a1770)
print $another_ref2,"\n";   #REF(0x104a1770)
print @$$another_ref,"\n";  #12345678910

2011年10月18日 星期二

Perl :use strict sub;

#strictSub.pl


use strict 'subs';
    #$SIG{PIPE} = Plumber;   # blows up
    $SIG{PIPE} = "Plumber"; # just fine: quoted string is always ok
    $SIG{PIPE} = \&Plumber; # preferred form

Perl :strict var

#strictVar.pl


 use strict 'vars';
    $X::foo = 1; # ok, fully qualified
    my $foo = 10; # ok, my() var
#    local $foo = 9; # blows up
##note:
##The local() generated a compile-time error because you just touched a global name without fully qualifying it.
##Because of their special use by sort(), the variables $a and $b are exempted from this check.


    package Cinna;
    our $bar; # Declares $bar in current package
    $bar = 'HgS'; # ok, global declared via pragma
    1;


print $Cinna::bar;     #Print out the var $bar in package 'Cinna'




#輸出結果:
HgS

Perl : use strict 'refs';

#strictStudy.pl


use strict 'refs';
$ref = \$foo;
print $$ref;
$ref = "foo";


#print $$ref;
#note:symbolic reference forbidden.


$file = "STDOUT";
$file2 = "STDIN";
print $file," Hi!";
#note:function case is exception case.
$bar = \&{'foo'}; #$bar get ref to function foo
&$bar;#Use &$bar to invoke the referenced function.


sub foo{
    print "foo function invoked..\n";
}
sub bar{
    print "bar function invoked...\n";
}


#輸出結果:
STDOUT Hi!foo function invoked..

TOPIC : How to push reference to Array

# TOPIC : How to push reference to Array
#use strict;
$myStr = "Hello,stayhigh.Do you want to be the best hacker?";
$myStr2=" Nice to meet you!";
#@test = split(" ",$myStr);
#print "testing :",@test,"\n";


push @$result ,[split(" ",$myStr)];
push @$result ,[split(" ",$myStr2)];
print "here:",@$result,"\n";
for (@$result){
    #$refToEle = $_;
    print "\$refToEle  result:",$_,"\n";#$refToEle,"\n";
    print "\@\$refToEle result:",@$_ ,"\n"#@$refToEle,"\n";
    
}

#輸出結果
here:ARRAY(0x104a1878)ARRAY(0x104a1818)
$refToEle  result:ARRAY(0x104a1878)
@$refToEle result:Hello,stayhigh.Doyouwanttobethebesthacker?
$refToEle  result:ARRAY(0x104a1818)
@$refToEle result:Nicetomeetyou!

#refFunc.pl




sub somefunc{
  print "function invoked:",$_[0],"\n";
  return $_[0];
}
#將函數的返回值傳入陣列@LoL的元素
for $i ( 1 .. 10 ) {
        $LoL[$i] = somefunc($i) ;
    }
    
print "\@LoL=>",@LoL,"\n";


#使用list reference [] @refArr陣列元素存入函數的參照
for $i ( 1 .. 10 ) {
        $refArr[$i] = [somefunc($i)] ;
    }
print "\@refArr => @refArr";


#輸出結果

function invoked:1
function invoked:2
function invoked:3
function invoked:4
function invoked:5
function invoked:6
function invoked:7
function invoked:8
function invoked:9
function invoked:10
@LoL=>12345678910
function invoked:1
function invoked:2
function invoked:3
function invoked:4
function invoked:5
function invoked:6
function invoked:7
function invoked:8
function invoked:9
function invoked:10
@refArr =>  ARRAY(0x104a1890) ARRAY(0x104a18c0) ARRAY(0x104a1908) ARRAY(0x104a1950) ARRAY(0x104a1998) ARRAY(0x104a19e0) ARRAY(0x104a1a28) ARRAY(0x104a1a70) ARRAY(0x104a1ab8) ARRAY(0x104a1b00)



Perl ->Avoid Symbolic References

Perl Style: Avoid Symbolic References

  • Beginners often think they want to have a variable contain the name of a variable.
    $fred    = 23;
        $varname = "fred";
        ++$$varname;         # $fred now 24
  • This works sometimes, but is a bad idea. They only work on global variables. Global variables are bad because they can easily collide accidentally.
  • They do not work under the use strict pragma
  • They are not true references and consequently are not reference counted or garbage collected.
  • Use a hash or a real reference instead.

Forward to Using A Hash Instead of $$name
Back to Avoid Byte Processing
Up to index
Copyright © 1998, Tom Christiansen
All rights reserved.







#symbolicRef.pl


$var    = 23;
$varnameref = "var";
++$$varnameref;         # $fred now 24
print $var,"\n";




@arr  =(1..10);
$arrnameref = "arr";
print @$arrnameref,"\n";


%hash = (
  k1 => "v1",
  k2 => "v2",
);


$hashnameref = "hash";
print %$hashnameref;


#輸出結果

24
12345678910
k2v2k1v1