Haskell関数の引数として2つの文字列が与えられています。
s1
が短い場合、s2
または同じ長さで辞書式順序が。よりも小さい場合よりも小さくなります。s1
s2
s1
s2
Haskellでこれを実装するにはどうすればよいですか?
次のようなものを使用します。
smaller :: String -> String -> Bool
smaller s1 s2 | len1 /= len2 = (len1 < len2)
| otherwise = (s1 < s2)
where (len1, len2) = (length s1, length s2)
Hugs で実行したサンプルを次に示します。
メイン>小さい「b」「aa」 真実 メイン>小さい「aa」「b」 間違い メイン>小さい「これ」「あれ」 間違い メイン > 小さい「あれ」「これ」 真実
ワンパス ソリューション:
lengthcompare :: Ord a => [a] -> [a] -> Ordering
lengthcompare = lc EQ
where
lc lx [] [] = lx
lc _ [] _ = LT
lc _ _ [] = GT
lc EQ (v:vs) (w:ws) = lc (compare v w) vs ws
lc lx (_:vs) (_:ws) = lc lx vs ws
smaller :: Ord a => [a] -> [a] -> Bool
smaller s1 s2 = lengthcompare s1 s2 == LT
これを試して:
compare s1 s2
(これはLT、EQ、またはGTを返します)。
mappend
上記の Tom Lokhorst によるバージョンの短いバージョン:
import Data.Monoid (mappend)
import Data.Ord (comparing)
compareStrings :: String -> String -> Ordering
compareStrings = comparing length `mappend` comparing id
タプルの順序付けを利用する別の方法:
import Data.Ord (comparing)
import Control.Arrow ((&&&))
compareStrings :: String -> String -> Ordering
compareStrings = comparing (length &&& id)
String
はのインスタンスであるOrd
ため、これらすべてのメソッドを使用して、文字列を辞書式に比較できます。Andrewが言ったように、それは本質的にcompare
だけでなく、(<)
とりわけ比較演算子でもあります。
smaller :: Ord a => a -> a -> Bool
smaller a b = a < b
これは、を含むすべてのタイプの実装で機能しますOrd
(実際にはの単なる粗いラッパーです(<)
)String
。
通常の文字列比較は、文字列の長さではなく、辞書式順序でのみ機能します。
したがって、長さもチェックするために独自の関数を作成する必要があります。
smaller :: String -> String -> Bool
smaller s1 s2 | length s1 < length s2 = True
| length s1 > length s2 = False
| otherwise = s1 < s2
またはもう少し一般的:
compareStrings :: String -> String -> Ordering
compareStrings s1 s2 | length s1 < length s2 = LT
| length s1 > length s2 = GT
| otherwise = compare s1 s2
例:
ghci> compare "ab" "z"
LT
ghci> compareStrings "ab" "z"
GT
Ord
私たちは先週、大学でモノイドをいじっていましたが、この素敵な代替インスタンスを思いつきました。
instance Ord a => Ord [a] where
compare = comparing length
`mappend` comparing head `mappend` comparing tail
しかし、これを完全に理解していない場合は、最初の定義に固執することをお勧めします;-)