Haskell: 编写一个函数,使其可以在列表上工作

Haskell: writing a function such that it can be lifted to work on lists

我有以下两个功能:

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

是否可以编写一个函数来 1) 完成 noneOnEmptyA 的功能,并且 2) 可以被提升以完成 noneOnEmptyB 的功能?问题的关键似乎是 noneOnEmptyA 检查空文本,而 noneOnEmptyB 检查空列表;但是,noneOnEmptyA lifted 以便对列表进行操作(如 fmap noneOnEmptyA 返回类型 [T.Text])检查列表中的空文本,而不是检查列表本身是否为空。

你可以做的一件事是引入一个类型类 Nullable

{-# LANGUAGE OverloadedStrings #-}
module Whosebug 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]

然后你就可以写你的函数了

noneOnEmpty :: (Nullable a, IsString a, Monoid a) => a -> a
noneOnEmpty a | isNull a = "None" <> mempty
              | otherwise = a

更新

正如@DanielWagner 指出的那样 - Monoid/mempty/<> 部分不是必需的

noneOnEmpty :: (Nullable a, IsString a) => a -> a
noneOnEmpty a | isNull a = "None"
              | otherwise = a