Bisakah `A =› Daftar[B]` diubah menjadi `Daftar[A =› B]`?

Saya mencoba menemukan implementasi untuk tanda tangan fungsi Scala ini:

def explode[A, B](f: A => List[B]): List[A => B]

Arah sebaliknya mungkin terjadi:

def nest[A, B](fs: List[A => B]): A => List[B] = (a: A) => fs.map(_(a))

Saat ini saya cenderung percaya bahwa yang pertama (explode) tidak dapat diterapkan, namun saya senang terbukti salah. Jika memang tidak memungkinkan untuk diterapkan, apakah ada alasan mendalam di baliknya?

Dalam pandangan saya, saya pada dasarnya meminta kompiler untuk menduplikasi input itu A beberapa n kali (ukuran Lists), dan memperbaikinya sebagai input.


person Eliav Lavi    schedule 26.12.2020    source sumber
comment
@LuisMiguelMejíaSuárez Lihat di sini . (Juga, tidak semuanya memiliki fungsi yang sama, masing-masing menghasilkan B yang berbeda)   -  person Eliav Lavi    schedule 27.12.2020
comment
Ya maaf. Saya masih berpikir ada baiknya menjelaskan apa yang ingin Anda lakukan   -  person Luis Miguel Mejía Suárez    schedule 27.12.2020
comment
Mengapa Anda tidak bekerja dengan daftar tupel? Atau Peta? Sesuatu seperti itu: def explode[A, B](f: A => List[B])(a: A): List[(A, B)] = { f(a).map(b => a -> b) } ?   -  person Tomer Shetah    schedule 27.12.2020


Jawaban (2)


Dalam pandangan saya, saya pada dasarnya meminta kompiler untuk menduplikasi input itu A beberapa n kali (ukuran Lists), dan memperbaikinya sebagai input.

Masalahnya adalah Anda tidak tahu apa n itu. Misalnya saja fungsi yang mengembalikan daftar semua pembagi prima suatu bilangan:

def divisors(n: Int): List[Int] = ???

Apa yang Anda harapkan dari explode(divisors)? divisors dapat mengembalikan List dengan ukuran berapa pun, bergantung pada argumennya, kapan pun ia dipanggil di masa mendatang. Namun saat Anda memanggil explode, ia harus segera mengembalikan List dengan ukuran tetap.

Mengingat tipe tetap A, tanda tangan dalam kode Anda dapat ditulis seperti ini:

type F[T] = List[T]
type G[T] = A => T

def nest[B]: F[G[B]] => G[F[B]]
def explode[B]: G[F[B]] => F[G[B]]

nest dan explode mengingatkan pada operasi sequence. Ini berfungsi untuk nest, karena dimungkinkan untuk menulis instance Traverse untuk List, tetapi tidak mungkin menulis instance Traverse untuk fungsi A => T. Berikut adalah pertanyaan yang setara untuk Haskell, yang memberi lebih banyak wawasan.

person Kolmar    schedule 26.12.2020
comment
Terima kasih atas tanggapan informatif Anda! Anda menulis: ...Tetapi ketika Anda memanggil nest ia harus segera mengembalikan Daftar dengan ukuran tetap. (Saya yakin maksud Anda explode). Dan itu benar. Saya mencoba memikirkan apakah jawabannya bisa berbeda jika saya bersedia segera menyerahkan bagian di mana daftar kembali dengan ukuran tetap - bagaimana jika saya bekerja dengan Stream / LazyList dll.? - person Eliav Lavi; 26.12.2020
comment
Menurut saya Stream masih kurang bagus, karena bisa langsung habis, misal. explode(divisors).toList. Dan List mungkin harus kosong untuk beberapa n. Apakah ini pertanyaan teoretis, atau Anda mempunyai masalah yang ingin dipecahkan? - person Kolmar; 26.12.2020
comment
Saya mengerti apa yang kamu maksud. Saya pikir List kosong bisa berfungsi dengan baik, tetapi intinya tetap utuh. Ini sebagian besar bersifat teoritis tetapi berasal dari proyek sampingan yang saya coba. Saya khawatir memberikan konteks yang lebih rinci akan terlalu rumit dan tidak akan membantu. Pada dasarnya ini berarti saya mungkin harus mencari arah lain dalam memodelkan masalah saya. - person Eliav Lavi; 27.12.2020

Jika Anda ingin membuat implementasi yang hanya memenuhi tanda tangan, Anda dapat melakukan sesuatu seperti ini:

def explode[A, B](f: A => List[B]): List[A => B] = {
  Nil
}

def explode[A, B](f: A => List[B]): List[A => B] = {
  List(f.andThen(_.head))
}

Tapi saya rasa Anda menginginkan sesuatu yang berbeda secara semantik:

duplikat input A itu beberapa n kali (ukuran Daftar), dan perbaiki sebagai input

Kalau begitu, ada masalah. Hasil dari f, secara umum, bergantung pada masukan A. Bisa berupa Nil, daftar ukuran terbatas, atau daftar tak terbatas.

Yang dapat Anda lakukan hanyalah sesuatu seperti:

def explode[A, B](f: A => List[B]): A => List[A => B] = {
  f.andThen(_.map(b => (_: A) => b)
}
person Artem Sokolov    schedule 26.12.2020