Могу ли я использовать нормальную форму значения, чтобы избежать неполных совпадений с образцом в Agda?

В следующей программе Agda я получаю предупреждение об отсутствующем падеже в определении one, несмотря на то, что myList подходит только к cons падежу.

open import Data.Nat

data List (A : Set) : Set where
  nil : List A
  cons : A → List A → List A

myList : List ℕ
myList = cons 1 (cons 2 (cons 3 nil))

one : ℕ
one with myList 
... | (cons x xs) = x
Incomplete pattern matching for .test.with-16. Missing
cases:
  one | nil

Я знаю, что это звучит немного запутанно, но есть ли способ определить one с точки зрения myList, не сталкиваясь с ошибками «неполного сопоставления с образцом»?

Этот пример является упрощением моей исходной задачи, взятой из домашнего задания и использующей несколько более сложные типы. В этом случае "myList" — это большое значение, вычисленное умной функцией на основе небольших входных данных. Если я вычислю нормальную форму "myList", используя режим Agda Emacs (C-c C-n), я смогу взять из него значение "one" и вставить его в свою программу. Однако при выводе это значение занимает десятки строк, поэтому я размышлял, есть ли способ напрямую определить "one" в терминах "myList", не сталкиваясь с ошибкой неполного сопоставления с образцом.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
120
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если вы используете with e, то e абстрагируется (представьте себе лямбда-абстракцию) от цели и контекста, и вас просят продолжить, как если бы у вас была переменная вместо самой e. Таким образом, следующее сопоставление с образцом вообще не учитывает значение myList (что довольно нелогично, но это просто синтаксический сахар для создания вспомогательного определения с одним дополнительным аргументом).

Однако вы можете написать следующее:

open import Agda.Builtin.List
open import Agda.Builtin.Nat renaming (Nat to ℕ)
open import Agda.Builtin.Equality

myList : List ℕ
myList = 1 ∷ 2 ∷ 3 ∷ []

head : {n : ℕ} {ns : List ℕ} (xs : List ℕ) → n ∷ ns ≡ xs → ℕ
head (x ∷ xs) refl = x

one : ℕ
one = head myList refl

Вы также можете посмотреть шаблон inspect в стандартной библиотеке для более общего решения этой проблемы.

Кажется, это помогает! Но знаете ли вы, есть ли разница в производительности между вычислениями x этим способом и использованием обычной формы (C-c C-n в Emacs)? В моем более крупном примере нормальная форма может быть вычислена очень быстро, но эта «проверочная» версия потребляет гигабайты ОЗУ и быстро начинает подкачку.

hugomg 28.05.2019 17:52

могут быть различия, потому что myList теперь просматривается во время проверки типа, чтобы убедиться, что это _∷_, и извлечь две части при проверке типа определения one

Saizan 06.06.2019 13:45
Ответ принят как подходящий

Вы можете отразить значение на уровне типа, а затем сопоставить его с образцом. Выглядит так:

open import Data.Nat

data List (A : Set) : Set where
  nil : List A
  cons : A → List A → List A

myList : List ℕ
myList = cons 1 (cons 2 (cons 3 nil))

data Sing {α} {A : Set α} : A -> Set where
  sing : ∀ x -> Sing x

one : ℕ
one with sing myList
... | sing (cons x (cons _ (cons _ nil))) = x

Эта версия отлично сработала с моей первоначальной проблемой (оценщик лямбда-исчисления)! У вас есть какие-либо идеи, почему это решение было более эффективным, чем решение «refl», предложенное Сайзаном?

hugomg 30.05.2019 00:58

@hugomg, извините, не знаю, почему решение refl неэффективно. Я предлагаю попробовать спросить в списке рассылки Agda. Это может оказаться сообщением об ошибке.

user3237465 30.05.2019 10:27

Другие вопросы по теме