Real World Haskell, bab 4, halaman 98 dari cetakan bertanya apakah words
dapat diimplementasikan menggunakan lipatan, dan ini juga pertanyaan saya:
Apa itu mungkin? Jika tidak, mengapa? Jika ya, bagaimana?
Saya datang dengan berikut ini, yang didasarkan pada gagasan bahwa setiap non-spasi harus ditambahkan ke kata terakhir dalam daftar output (ini terjadi di otherwise
penjaga), dan bahwa ruang harus memicu penambahan kata emtpy ke daftar keluaran jika belum ada (ini ditangani di if
- then
- else
).
myWords :: String -> [String]
myWords = foldr step [[]]
where
step x yss@(y:ys)
| x == ' ' = if y == "" then yss else "":yss
| otherwise = (x:y):ys
Jelas solusi ini salah, karena spasi spasi pada string input menghasilkan satu string kosong terkemuka di daftar output string.
Pada tautan di atas, saya telah melihat ke beberapa solusi yang diusulkan untuk pembaca lain, dan banyak dari mereka bekerja mirip dengan solusi saya, tetapi mereka umumnya "pasca-proses" output flip, misalnya dengan tail
memasukkannya jika ada adalah string terkemuka yang kosong.
Pendekatan lain menggunakan tupel (sebenarnya hanya berpasangan), sehingga lipatan berurusan dengan pasangan dan dapat dengan baik menangani ruang terkemuka / trailing.
Dalam semua pendekatan ini, foldr
(atau lipatan lain, fwiw) bukan fungsi yang memberikan hasil akhir dari kotak; selalu ada hal lain dengan harus menyesuaikan output entah bagaimana.
Oleh karena itu saya kembali ke pertanyaan awal dan bertanya apakah itu benar-benar mungkin untuk diterapkan words
(dengan cara yang benar menangani trailing / spasi / spasi berulang) menggunakan lipatan. Dengan menggunakan lipatan, maksud saya bahwa fungsi lipatan harus merupakan fungsi terluar:
myWords :: String -> [String]
myWords input = foldr step seed input
sumber
["xa"] == words "xa" == step 'x' (words "a") == step 'x' (words " a") == words "x a" == ["x", "a"]
, yang memiliki manfaat menjadi argumen yang valid untuk kedua arah lipatan@chi memiliki argumen yang bagus yang tidak dapat Anda terapkan
words
dengan menggunakan lipatan "a", tetapi Anda mengatakan menggunakan lipatan s .Baik fungsi terluar maupun terdalam adalah lipatan. ;-)
sumber
Iya. Meskipun sedikit rumit, Anda masih dapat melakukan pekerjaan ini dengan benar dengan menggunakan satu
foldr
dan tidak ada yang lain jika Anda tinggal di CPS ( Continuation Passing Style ). Saya telah menunjukkan jenischunksOf
fungsi khusus sebelumnya.Dalam jenis lipatan akumulator kami, maka hasil lipatan adalah fungsi dan kami harus menerapkannya pada jenis input identitas sehingga kami mendapatkan hasil akhir. Jadi ini dapat dihitung sebagai tahap pemrosesan akhir atau tidak karena kita menggunakan lipatan tunggal di sini dan jenisnya termasuk fungsi. Terbuka untuk diperdebatkan :)
sf
: Nilai fungsi awal untuk memulai.go
: Fungsi iteratorKami sebenarnya tidak sepenuhnya memanfaatkan kekuatan CPS di sini karena kami memiliki karakter sebelumnya
pc
dan karakter arus yangc
ada di setiap kesempatan. Itu sangat berguna dalamchunksOf
fungsi tersebut di atas sementara chunking sebuah[Int]
ke[[Int]]
setiap kali urutan menaik elemen yang rusak.sumber