WalzoneInterview Prep
📞 Interviewing soon? Practice with a realistic AI mock phone interview — it calls you, then scores you. First 15 min FREE →

Haskell · Expert · question 71 of 100

Can you describe a use case for "Dependent Types" in Haskell?

📕 Buy this interview preparation book: 100 Haskell questions & answers — PDF + EPUB for $5

Dependent types are types that depend on values. They can be useful for ensuring stronger compile-time guarantees about the correctness and behavior of your code. In Haskell, you can utilize dependent types with the help of extensions like ‘DataKinds‘, ‘TypeFamilies‘, ‘GADTs‘, and ‘RankNTypes‘. Some of these features are not true dependent types as found in languages like Agda or Idris, but they can allow a form of dependent typing.

Here’s a use case of dependent types in Haskell, focusing on a scenario where we have a list of vectors with statically known lengths.

1. First, let’s define a type-level natural number to represent the length of the vectors. We’ll use ‘GHC.TypeLits‘ for this purpose.

{-# LANGUAGE DataKinds, KindSignatures #-}

import GHC.TypeLits

data Nat = Z | S Nat

2. Now, we will define a ‘Vector‘ data type with a type-level length parameter, using the ‘GADTs‘ extension.

{-# LANGUAGE GADTs #-}

data Vector (n :: Nat) a where
  VNil :: Vector 'Z a
  VCons :: a -> Vector n a -> Vector ('S n) a

3. With this setup, we can define functions that work on vectors while enforcing the correct lengths at the type level. For example, let’s define a ‘vZipWith‘ function, which takes a binary operation and two vectors, and produces a vector containing the result of applying the operation element-wise:

vZipWith :: (a -> b -> c) -> Vector n a -> Vector n b -> Vector n c
vZipWith _ VNil VNil = VNil
vZipWith f (VCons x xs) (VCons y ys) = VCons (f x y) (vZipWith f xs ys)

Here, it is guaranteed that the input vectors have the same length, and the output vector will have the same length as the input vectors.

4. As an example, consider we have two vectors v1 and v2 with lengths 2 and 3, respectively:

v1 :: Vector ('S ('S 'Z)) Int
v1 = VCons 1 (VCons 2 VNil)

v2 :: Vector ('S ('S ('S 'Z))) Int
v2 = VCons 1 (VCons 2 (VCons 3 VNil))

Now, if we try to call ‘vZipWith‘ with ‘v1‘ and ‘v2‘, the type system will disallow this, as the lengths of these vectors are not the same:

v3 = vZipWith (+) v1 v2
error: Wildcard '_' occurs as defined/fixed by: 'S 'Z ~ 'S ('S 'Z), couldn't match type 'S 'Z with 'S ('S 'Z), in the first argument of 'Vector'.

Dependent types are useful in cases where you want to maintain stronger invariants at the type level, leading to fewer runtime errors and incorrect behavior. The use of dependent types can make your code safer and more reliable.

Reading is step one. Saying it out loud is the interview. Our AI interviewer calls your phone and runs a realistic Haskell interview — then scores it.
📞 Practice Haskell — free 15 min
📕 Buy this interview preparation book: 100 Haskell questions & answers — PDF + EPUB for $5

All 100 Haskell questions · All topics