Nope, this offers no performance increase whatsoever. In both cases the compiler has to evaluate the argument to it's WHNF to check whether it's the empty list or not.
Actually, it is pretty likely that this function will be rewritten during compilation an generate code entirely different from what you wrote (assuming you compiled with optimizations).
Looking at the generated core (compiled without optimizations):
(letrec {
f1_aLn [Occ=LoopBreaker] :: [Integer] -> Integer
[LclId, Arity=1, Str=DmdType]
f1_aLn =
\ (ds_d1gX :: [Integer]) ->
case ds_d1gX of _ [Occ=Dead] {
[] -> fromInteger @ Integer GHC.Num.$fNumInteger 0;
: ds1_d1h4 xs_at0 ->
+ @ Integer
GHC.Num.$fNumInteger
(fromInteger @ Integer GHC.Num.$fNumInteger 1)
(f1_aLn xs_at0)
}; } in
f1_aLn (enumFromTo @ Integer GHC.Enum.$fEnumInteger 1 100))
(letrec {
f2_aBk [Occ=LoopBreaker] :: [Integer] -> Integer
[LclId, Arity=1, Str=DmdType]
f2_aBk =
\ (ds_d1gP :: [Integer]) ->
case ds_d1gP of _ [Occ=Dead] {
[] -> fromInteger @ Integer GHC.Num.$fNumInteger 0;
: ds1_d1gW xs_aBh ->
+ @ Integer
GHC.Num.$fNumInteger
(fromInteger @ Integer GHC.Num.$fNumInteger 1)
(f2_aBk xs_aBh)
}; } in
f2_aBk (enumFromTo @ Integer GHC.Enum.$fEnumInteger 1 100))
We can see that the compiler generates equivalent statements. Just fyi, this was the code:
main = do
print $ f1 [1..100]
print $ f2 [1..100]
f1 [] = 0
f1 (_:xs) = 1 + f1 xs
f2 (_:xs) = 1 + f2 xs
f2 [] = 0
compiled with ghc -ddump-simpl file.hs