Haskell中的元音数据类型,有可能吗?

Ric*_*sse 7 haskell types functional-programming pattern-matching

我写了以下代码来删除句子中的元音:

   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
Run Code Online (Sandbox Code Playgroud)

只是想知道是否可以为元音创建数据类型?编译器不允许我在数据类型中使用字符.

Joh*_*n L 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
Run Code Online (Sandbox Code Playgroud)

由于Vowel未导出构造函数,因此只能Vowelvowel函数创建new s,该函数只允许您想要的字符.

您也可以创建一个这样的新类型:

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'
Run Code Online (Sandbox Code Playgroud)

第二种方式非常重量级,因此使用起来更加笨拙.

这就是如何做到的.我不太确定你想要的.通常的成语是使代表你的数据类型,并且你特别代表元音.一个常见的模式是这样的:

newtype CleanString = Cleaned { raw :: String }

-- user input needs to be sanitized
cleanString :: String -> CleanString
Run Code Online (Sandbox Code Playgroud)

这里newtype区分未经过消毒和已消毒的输入.如果制作a的唯一方法CleanStringcleanString,那么你就会静静CleanString地知道每一个都经过适当的消毒(前提是这cleanString是正确的).在你的情况下,你似乎确实需要一个辅音类型,而不是元音.

Haskell中的Newtypes非常轻量级*,但程序员必须编写并使用代码来进行包装和解包.在许多情况下,好处超过了额外的工作.但是,我真的想不出任何重要的事情,知道你String的元音是免费的,所以我可能只是简单地工作String.

*newtypes仅在编译时存在,因此理论上使用它们没有运行时性能成本.但是,它们的存在可以改变生成的代码(例如,禁止RULE),因此有时会产生可测量的性能影响.


sha*_*ang 8

您可以使用幻像类型来标记带有额外信息的字符,以便在编译期间使类型系统保证您的字符串仅包含元音或非元音.

这是一个玩具示例:

{-# 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
Run Code Online (Sandbox Code Playgroud)

这种方法的好处是你仍然可以编写适用于所有TaggedChars的函数,无论标记如何.例如:

toString :: [TaggedChar a] -> String
toString = map fromTaggedChar
Run Code Online (Sandbox Code Playgroud)