{- |
Description: Extract a slice from a list
Copyright: Copyright (C) 2021 Yoo Chung
License: GPL-3.0-or-later
Maintainer: dev@chungyc.org

Some solutions to "Problems.P18" of Ninety-Nine Haskell "Problems".
-}
module Solutions.P18 (slice,slice') where

-- | Extract a slice from a list.
--
-- Given two indices, @i@ and @k@, the slice is the list containing the elements
-- between the @i@'th and @k@'th element of the original list, with both limits included.
-- Start counting the elements with 1.
--
-- Go through individual elements in the list, dropping them and then keeping some of the rest.
slice :: [a] -> Int -> Int -> [a]
slice :: forall a. [a] -> Int -> Int -> [a]
slice [] Int
_ Int
_ = []
slice [a]
xs Int
1 Int
m = [a] -> Int -> [a]
forall a. [a] -> Int -> [a]
extract [a]
xs Int
m
slice (a
_:[a]
xs) Int
n Int
m
  | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1     = [a] -> Int -> Int -> [a]
forall a. [a] -> Int -> Int -> [a]
slice [a]
xs (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) (Int
mInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1)
  | Bool
otherwise = [a]
forall a. HasCallStack => a
undefined

extract :: [a] -> Int -> [a]
extract :: forall a. [a] -> Int -> [a]
extract [] Int
_ = []
extract (a
x:[a]
_) Int
1 = [a
x]
extract (a
x:[a]
xs) Int
n
  | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0     = a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a] -> Int -> [a]
forall a. [a] -> Int -> [a]
extract [a]
xs (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1)
  | Bool
otherwise = [a]
forall a. HasCallStack => a
undefined

-- | Extract a slice from a list.
--
-- Given two indices, @i@ and @k@, the slice is the list containing the elements
-- between the @i@'th and @k@'th element of the original list, with both limits included.
-- Start counting the elements with 1.
--
-- 'drop' and then 'take'.
slice' :: [a] -> Int -> Int -> [a]
slice' :: forall a. [a] -> Int -> Int -> [a]
slice' [a]
l Int
n Int
m = Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take (Int
mInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) [a]
l