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
我有以下两个功能:
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