Home > Software design >  How to iterate through `newtype` List in Haskell
How to iterate through `newtype` List in Haskell

Time:10-13

For that newtype is treated as a whole different type in the type system, I'm wondering if there is any way to use pattern matching or iterate a list with newtype, as follow.

newtype Foo = Foo [Int]

bar :: Foo -> Int
bar (x : xs) = x   bar xs
bar [] = 0

CodePudding user response:

There are multiple options.

  1. Just manually wrap/unwrap the newtype right in place.

    bar (Foo (x : xs)) = x   bar (Foo xs)
    bar (Foo []) = 0
    
  2. Implement the function on lists, and unwrap it once before passing to the function. In this case the list version is just sum, so we can use

    bar (Foo xs) = sum xs
    
  3. Make an interface that allows to manipulate Foo values as if they were lists.

    {-# LANGUAGE PatternSynonyms #-}
    
    {-# COMPLETE (:%), FooNil #-}
    
    pattern (:%) :: Int -> Foo -> Foo
    pattern x :% xs <- Foo (x : (Foo -> xs))
     where x :% xs = Foo (x : getFoo xs)
    
    pattern FooNil :: Foo
    pattern FooNil = Foo []
    
    bar :: Foo -> Int
    bar (x :% xs) = x   bar xs
    bar FooNil = 0
    
  4. Abstract. You don't really need the particular list deconstructors, you just need some way to implement a fold over the contained data. There is a standard Foldable class in base for just this, but it would require you container to be parametric over the contained type. Since it's not parametric, you need to use MonoFoldable class from the mono-traversable package instead.

    import Data.MonoTraversable
    
    type instance Element Foo = Int
    import MonoFoldable Foo where
      ofoldr f (Foo (x:xs)) e = f x $ ofoldr f (Foo xs) e
      ofoldr _ (Foo []) e = e
    
    bar = ofoldr ( ) 0
    

Note that generally, this sort of function should be implemented with a strict left fold instead of a right fold.

  • Related