I have the following 2 functions:
import qualified Data.Text as T
noneOnEmptyA :: T.Text -> T.Text
noneOnEmptyA txt | T.null txt = "None."
| otherwise = txt
noneOnEmptyB :: [T.Text] -> [T.Text]
noneOnEmptyB txts | null txts = ["None."]
| otherwise = txts
Is it possible to write a single function that 1) accomplishes what noneOnEmptyA
does, and 2) can be lifted such that it accomplishes what noneOnEmptyB
does? The crux of the problem seems to be that noneOnEmptyA
checks for empty text, while noneOnEmptyB
checks for an empty list; however, noneOnEmptyA
lifted so as to operate on lists (as in fmap noneOnEmptyA
returning type [T.Text]
) checks for empty text inside the list, rather than checking whether or not the list itself is empty.
one thing you could do is introduce a typeclass Nullable
{-# LANGUAGE OverloadedStrings #-}
module Stackoverflow where
import Data.Text (Text)
import qualified Data.Text as T
import Data.Monoid
import Data.String
class Nullable a where
isNull :: a -> Bool
instance Nullable Text where
isNull = T.null
instance IsString a => IsString [a] where
fromString str = [fromString str]
then you can write your function
noneOnEmpty :: (Nullable a, IsString a, Monoid a) => a -> a
noneOnEmpty a | isNull a = "None" <> mempty
| otherwise = a
As @DanielWagner points out - the Monoid
/mempty
/<>
part is not necessary
noneOnEmpty :: (Nullable a, IsString a) => a -> a
noneOnEmpty a | isNull a = "None"
| otherwise = a