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
There are multiple options.
Just manually wrap/unwrap the newtype right in place.
bar (Foo (x : xs)) = x + bar (Foo xs)
bar (Foo []) = 0
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
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
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.