2009-05-04 12 views

cevap

9

Ben istiyorum sopa ile öneririz: üniversite geçen hafta ve biz bu güzel alternatif Ord örneği ile geldi aşağıdaki gibi bir şey kullanın:

İşte
smaller :: String -> String -> Bool 
smaller s1 s2 | len1 /= len2   = (len1 < len2) 
       | otherwise   = (s1 < s2) 
       where (len1, len2) = (length s1, length s2) 

Hugs içinde, örnek bir çalışma var:

 
Main> smaller "b" "aa" 
True 
Main> smaller "aa" "b" 
False 
Main> smaller "this" "that" 
False 
Main> smaller "that" "this" 
True 
+0

Bu, benim sürümümden açıkça daha hızlıdır, çünkü yalnızca dizelerin uzunluğunu bir kez hesaplar. Giriş dizgileri üzerinde doğrudan bir desen eşleştirmesi yapılarak daha da hızlı yapılabilir, böylece bu tanım ve uzunluk fonksiyonunun tanımı birleştirilir. –

+1

Haskell, genelleştirme ve iyi kodlama uygulamaları ile ilgilidir ve çok iyi bir tip (sınıf) sistemine sahiptir. Neden işlevi "karşılaştır" olarak yeniden yazmayın: Ord a => [a] -> [a] -> Sıralama 'veya benzeri? –

+1

@Aleksander: OP'nin istediği şeye bağlıdır.OP oldukça basit bir soru sorduğundan, belki de temel bir cevap istiyordur? Haskell'de böyle bir işlevi yazmanın daha hızlı ve/veya daha fazla deyim taşıdığından şüphe etmiyorum, ancak OP'nin öğrenmesine yardımcı olmak için işleri basit tutmak daha iyidir. –

5

bu deneyin:

compare s1 s2 

(Bu LT, EQ veya GT döner).

+0

Bence OP, daha kısa dizelerden, içeriğinden bağımsız olarak daha uzun dizelerden daha küçük olmasını istiyor. karşılaştırmak "b" "aa", GT'yi döndürür, ancak OP'nin bu durumda LT'i döndüren bir işlev isteyeceğini düşünüyorum. –

2

String, Ord'un bir örneğidir ve bu nedenle, sözdizimsel olarak dize karşılaştırmak için tüm bu yöntemleri kullanabilirsiniz. Andrew'un dediği gibi, bu aslında compare ama aynı zamanda karşılaştırma operatörleri, diğerleri arasında (<).

smaller :: Ord a => a -> a -> Bool 
smaller a b = a < b 

Bu Ord uygulayan her türlü için çalışıyor (ve (<) için gerçekten sadece bir ham sarıcı) String dahil.

+0

Bence OP, içeriğinden bağımsız olarak daha kısa dizelerden daha küçük dizelerden daha küçük dizeler istiyor. Örneğin, daha küçük "b" "aa" True değerini döndürmelidir. (<) uzunlukları hesaba katmaz, bu yüzden cevabınızın OP'nin ne istediği konusunda tam olarak olduğuna inanmıyorum. –

2

Normal dize karşılaştırması, yalnızca dizgilerin uzunluğu değil, sözlüksel sıralamayla çalışır.Daha genel

smaller :: String -> String -> Bool 
smaller s1 s2 | length s1 < length s2 = True 
       | length s1 > length s2 = False 
       | otherwise    = s1 < s2 

Veya biraz:

compareStrings :: String -> String -> Ordering 
compareStrings s1 s2 | length s1 < length s2 = LT 
        | length s1 > length s2 = GT 
        | otherwise    = compare s1 s2 

Örnek:

ghci> compare "ab" "z" 
LT 
ghci> compareStrings "ab" "z" 
GT 

yüzden de uzunluk için kontrol etmek için kendi işlevi yazmak zorunda kalacak

Monoids ile etrafta dolaşıyorduk

instance Ord a => Ord [a] where 
    compare = comparing length 
       `mappend` comparing head `mappend` comparing tail 

oldukça bu anlamıyorum Ama eğer ben ilk tanım ;-)

+2

Uzunlukları karşılaştırmanın nedeninin bir kısmı yararlıdır, diğer dillerdeki String uygulamalarının çoğu, string uzunluğunu depolar veya önbelleğe alır. Yarar, çoğu dize karşılaştırmasının, daha sonra dizilerin uzunluklarının bir fonksiyonu olarak O (1) zamanını alacağıdır. Bu Haskell'de durum böyle değil. Yerel uygulama ile tüm String karşılaştırmaları, dizelerin uzunluklarının bir fonksiyonu olarak en az O (min (m, n)) zaman alacaktır. – yfeldblum

+2

Elbette, bu bile mümkün olan en hızlı uygulama değildir. Sadece sorgusun, sözlüklerin sözel dizilimden önce uzunluğun ilk kontrol edildiği bir karşılaştırma sürümü istediğini sanmıştım. Dizelerin bir listesini yazdırmak ve daha önce küçük dizeleri yazdırmak için daha güzel düşünmek istiyorsanız, bu yararlı olabilir. –

+0

@ Tez: S2 s1'den uzunsa, daha küçük işlevinizin doğru çalıştığından emin değilim. Örneğin, daha küçük "aa" "b", True değerini döndürür. Bana öyle geliyor ki, OP bu durumda False'yi geri döndürme işlevini istiyor. –

7

tek geçişli çözüm:

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 
4

Tom Lokhorst tarafından mappend sürümünün bir kısa versiyonu yukarıda:

import Data.Monoid (mappend) 
import Data.Ord (comparing) 

compareStrings :: String -> String -> Ordering 
compareStrings = comparing length `mappend` comparing id 

başka yolu da, dizilerini sipariş yararlanarak:

import Data.Ord (comparing) 
import Control.Arrow ((&&&)) 

compareStrings :: String -> String -> Ordering 
compareStrings = comparing (length &&& id) 
+0

Doğru, alternatif bir tanım düşünmekteydim, ancak yeni bir işlevi tanımlarken, mevcut sipariş listelerinde açık bir şekilde kullanabilirsiniz. Güzel tanımlar! –

+0

Ayrıca, Oklar kitaplığını öğrenmeye gerçekten ihtiyacım var. Sürekli olarak bu güzel ve zarif tanımlarla gelen insanları görüyorum ve bu sadece işlev örneklerini kullanıyor ... –

+0

Evet, bunlar güzel ve kısa. id == karşılaştırın karşılaştırması, işte burada başka bir alternatif: karşılaştırma 'mappend' karşılaştırması – Martijn