Implementing Haskell's `insert`
In my experience idiomatic Haskell does not use if/else very much. Guards are definitely the preferred approach. The idea is to have the core of your logic in a function and let the checks and edge cases be handled at the edges. This also tends to end up with cleaner, more open code. Using the guard lets the reader see exactly what is happening without having to look inside the if/else branches.

insert' :: (Ord a) =&gt; a -&gt; [a] -&gt; [a]
insert' x []         = [x]
insert' x yys@(y:ys)
  | x &lt;= y           = x : yys
  | otherwise        = y : insert' x ys


If you are concerned about speed, the compiler transforms the guards and the if/else into the same case structure internally. I made a simple main:

main = putStrLn $ show $ insert' 2 $ insert' 4 [3,2,1]


Below is the relevant section from ghc -O2 -ddump-simpl insert.hs. I added comments to shows where your original code is to help you read it.

Rec {
Main.main_$sinsert' [Occ=LoopBreaker]
  :: GHC.Integer.Type.Integer
     -&gt; [GHC.Integer.Type.Integer] -&gt; [GHC.Integer.Type.Integer]
[GblId, Arity=2, Caf=NoCafRefs, Str=DmdType LS]
Main.main_$sinsert' =
  \ (x_akb :: GHC.Integer.Type.Integer)
    (ds_dxR :: [GHC.Integer.Type.Integer]) -&gt;
    case ds_dxR of wild_X8 {
      [] -&gt;
        GHC.Types.:
          @ GHC.Integer.Type.Integer
          x_akb
          (GHC.Types.[] @ GHC.Integer.Type.Integer);  {- [x] case -} 
      : y_ake ys_akf -&gt;
        case GHC.Integer.Type.leInteger x_akb y_ake of _ {
          GHC.Types.False -&gt;
            GHC.Types.:
              @ GHC.Integer.Type.Integer
              y_ake
              (Main.main_$sinsert' x_akb ys_akf); {- recurse -}
          GHC.Types.True -&gt;
            GHC.Types.: @ GHC.Integer.Type.Integer x_akb wild_X8 {- return of final list -}
        }
    }
end Rec }