我已经编写了以下代码来删除句子中的元音:
main = print $ unixname "The House"
vowel x = elem x "aeiouAEIOU"
unixname :: [Char] -> [Char]
unixname [] = []
unixname (x:xs) | vowel x = unixname xs
| otherwise = x : unixname xs
只是想知道是否可以为元音创建数据类型?编译器不允许我在数据类型中使用字符。
答案 0 :(得分:15)
不直接。问题是字符是内置类型,没有多态性。这与数字文字不同,后者通过Num
类型类设计为多态。
也就是说,您可以采用两种基本方法:带有智能构造函数的newtype包装器,或者全新的类型。
newtype包装器更易于使用:
module Vowel (Vowel, vowel, fromVowel) where
newtype Vowel = Vowel Char
vowel :: Char -> Maybe (Vowel)
vowel x | x `elem` "aeiouAEIOU" = Just (Vowel x)
| otherwise = Nothing
fromVowel :: Vowel -> Char
fromVowel (Vowel x) = x
由于Vowel
构造函数未导出,因此新Vowel
只能由vowel
函数创建,该函数只接受您想要的字符。
你也可以制作一个这样的新类型:
data Vowel = A | E | I | O | U | Aa | Ee | Ii | Oo | Uu
fromChar :: Char -> Maybe Vowel
fromChar 'a' = Just Aa
fromChar 'A' = Just A
-- etc.
toChar :: Vowel -> Char
toChar Aa = 'a'
toChar A = 'A'
第二种方式非常重要,因此使用起来更加尴尬。
这就是怎么做的。我不太确定你想要的。通常的习惯用法是制作代表您数据的类型,而您明确地不代表元音。一个常见的模式是这样的:
newtype CleanString = Cleaned { raw :: String }
-- user input needs to be sanitized
cleanString :: String -> CleanString
这里newtype区分未经过消毒和已消毒的输入。如果CleanString
的唯一方法是cleanString
,那么您静态地知道每个CleanString
都已正确清理(假设cleanString
正确)。在你的情况下,你似乎确实需要一个辅音类型,而不是元音。
Haskell中的Newtypes非常轻量级*,但程序员必须编写并使用代码来进行包装和解包。在许多情况下,好处超过了额外的工作。但是,我真的想不出任何重要的事情,知道你的String
是无元音的,所以我可能只使用普通的String
。
* newtypes仅在编译时存在,因此理论上使用它们没有运行时性能成本。但是,它们的存在可以改变生成的代码(例如,禁止RULE),因此有时会产生可衡量的性能影响。
答案 1 :(得分:8)
您可以使用phantom types标记带有额外信息的字符,以便在编译期间使字符串系统保证您的字符串仅包含元音或非元音。
这是一个玩具示例:
{-# LANGUAGE EmptyDataDecls #-}
import Data.Maybe
newtype TaggedChar a = TaggedChar { fromTaggedChar :: Char }
data Vowel
data NonVowel
isVowel x = x `elem` "aeiouyAEIOUY"
toVowel :: Char -> Maybe (TaggedChar Vowel)
toVowel x
| isVowel x = Just $ TaggedChar x
| otherwise = Nothing
toNonVowel :: Char -> Maybe (TaggedChar NonVowel)
toNonVowel x
| isVowel x = Nothing
| otherwise = Just $ TaggedChar x
unixname :: [Char] -> [TaggedChar NonVowel]
unixname = mapMaybe toNonVowel
这种方法的好处是,无论标记如何,您仍然可以编写适用于所有TaggedChars的函数。例如:
toString :: [TaggedChar a] -> String
toString = map fromTaggedChar