Haskell'de değerlerin öğelere ve ara öğelere dönüştürülmesi
Kullanıcı arabirimi programlaması yaparken, sık sık bir değerler listesi oluşturma ve işlenen değerler arasına bazı ilgili bilgileri ekleme ihtiyacıyla karşılaşıyorum. Aşağıdaki kod örneğinde, sayısal değerleri parantez içinde göründükleri dizelere dönüştürüyorum ve iki değerin mesafesini, değerlerin renderları arasına yerleştirilen bir dizeye dönüştürüyorum. Kod çalışıyor, ancak mystery
işlevin bir uygulamasının Haskell standart kitaplığının bir parçası olarak mevcut olup olmadığını merak ediyorum . Ayrıca, bu işlev için diğer kütüphanelerde kullanılan isimlerle de ilgileniyorum, çünkü insan tarafından okunabilir sözcükler kullanmak Google'da aramayı kolaylaştırıyor.
mystery :: (a -> b) -> (a -> a -> b) -> [a] -> [b]
mystery n d [] = []
mystery n d [x] = [n x]
mystery n d (x:xs) = (n x) : (d x (head xs)) : mystery n d xs
node x = "(" ++ show x ++ ")"
distance x y = "-" ++ (show $ abs $ x - y) ++ "-"
render xs = concat $ mystery node distance xs
-- render [25, 68, 54, 15] == "(25)-43-(68)-14-(54)-39-(15)"
Yanıtlar
Sizin mystery
işlevi aslında aynı anda birkaç şey yapıyor ve davranışları ayırmak, eğer neler görmek için biraz daha kolay olabilir.
İlk olarak, n
tüm unsurları eşleştiriyorsunuz . Bunu olarak yazabiliriz fmap n xs
. Ardından, d x y
tüm bitişik öğe çiftleri için yeni öğeler oluşturuyorsunuz x
ve y
. Bunu olarak yazabiliriz zipWith d xs (tail xs)
.
Son adım, bu iki yapıyı alıp aralarında gidip gelen unsurların yer aldığı yeni bir liste yapmaktır. İlginç bir şekilde, bu 9 yıl önce sorulan bir soruydu , ancak yine de süper tatmin edici bir cevabı yok. Muhtemelen en basit cevap kendi işlevinizi tanımlamaktır:
alternate [] ys = ys
alternate (x:xs) ys = x : alternate ys xs
Daha sonra mystery
tek satırlık olarak tanımlayabiliriz :
mystery n d x = alternate (fmap n x) (zipWith d x (tail x))
Eğer varsa gerçekten bunun tek astar olmak istiyorum, en iyi ben kullanıyordum ile gelebilir concat
ve transpose
korkak bir şekilde bu aralar biraz:
mystery n d x = concat $ transpose $ (pure $ fmap n x) <> (pure $ zipWith d x (tail x))
Temel olarak, iki bileşenden tekil listeler yapıyoruz pure
, bunları kullanarak , bunları birleştiriyoruz <>
, sonra transpose
öğeleri düzgün bir şekilde serpiştirmek için bu "liste listesi" ni oluşturuyoruz ve concat
sonucu elde ediyoruz .