2011-10-01 15 views
7

私は文から母音を削除するには、次のコードを書かれている:母音のデータ型を作成することが可能である場合ハスケルでの母音のデータ型は可能でしょうか?

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 

は不思議?コンパイラは、データ型の文字を使用することはできません。

+2

私は母音がUNIX名に許されなかったことに気づいていなかった;) –

+0

は、なぜあなたは「母音のデータ型」をしたいですか?それは何をするでしょうか? –

+2

@Anschel、おそらく 'Char'であり、その値は母音だけを取ることができます。これは 'unixname'の正当性基準の一つを宣言する方法です。実際に彼は補完が必要だからではありませんが、あなたはそのアイデアを得ます。 – luqui

答えて

15

直接ではありません。問題は、文字が多型のための機能を持たないビルトイン型であることです。これは、Numタイプのクラスを使用して多型になるように設計された数値リテラルとは異なります。

つまり、スマートコンストラクタを持つ新しいタイプのラッパー、まったく新しいタイプの2つの基本的なアプローチがあります。

の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 sが唯一の唯一の希望の文字を認めている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のNewtypeは非常に軽量ですが、プログラマはラッピングとアンラッピングを行うコードを記述して使用する必要があります。多くの場合、その利点は余分な作業を上回ります。しかし、私は本当にあなたのStringが母音でないことを知っていることを知っておくことが重要なアプリケーションについては考えていないので、おそらく普通のStringで作業しています。

* newtypesはコンパイル時にのみ存在するため、理論的にはnewtypesは実行時のパフォーマンスコストがありません。しかし、その存在は、生成されたコードを変更することがあり(例えば、ルールを抑制する)、測定可能なパフォーマンスの影響があることがあります。

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
関連する問題