Haskell: «переменная неоднозначного типа, возникающая в результате использования функции», где указанная переменная фактически не имеет значения - PullRequest
0 голосов
/ 08 ноября 2018

Рассмотрим следующую функцию:

foo :: Show a => Maybe a -> [Char] 
foo (Just x) = show x 
foo Nothing = "Nothing"

Затем я пытаюсь использовать эту функцию:

bar :: [Char]
bar = foo Nothing

Аргумент, который был передан foo, имеет тип Maybe a, где a не указан, и на самом деле нас не волнует a, потому что мы используем только регистр foo для Nothing. Но GHC утверждает, что предоставил конкретный тип:

Неопределенная переменная типа a0, возникающая в результате использования foo
препятствует разрешению ограничения (Show a0). вероятный исправление: используйте аннотацию типа, чтобы указать, что a0 должно быть.

GHC подсказывает, чтобы указать тип. Таким образом, единственное исправление, которое я вижу, это создание поддельного типа, который имеет экземпляр класса Show:

{-# LANGUAGE EmptyDataDecls, KindSignatures #-}
{-# OPTIONS_GHC -fno-warn-missing-methods #-}

data Dummy :: *

instance Show Dummy

bar :: [Char]
bar = foo (Nothing :: Maybe Dummy)

foo :: Show a => Maybe a -> [Char]
foo (Just x) = show x
foo Nothing = "Nothing"

Это работает, но кажется довольно простым. Но настоящая причина, почему мне не нравится это решение, состоит в том, что для моих целей этот код автоматически генерируется из некоторых метаданных, которые не предоставляют информацию о том, какой конкретный тип полиморфа должен быть указан как Dummy (могут быть пользовательские типы данных с более чем одним параметром). Поэтому мне интересно, есть ли способ сказать GHC, что если тип не указан, этот тип не имеет значения?

Ответы [ 2 ]

0 голосов
/ 08 ноября 2018

Средство проверки типов не знает, что foo делает со своим аргументом, и, в частности, не знает, что Nothing фактически не будет использоваться. Но он знает , что аргумент должен иметь тип Show a => Maybe a, а Nothing имеет более общий тип Maybe a. Вы должны предоставить достаточно узко типизированный аргумент при вызове foo.

Нет необходимости определять новый фиктивный тип; подойдет любой существующий тип с экземпляром Show.

bar :: [Char]
bar = foo (Nothing :: Maybe ())
0 голосов
/ 08 ноября 2018

«не имеет значения» является свойством экземпляра, и ghc не анализирует подобные экземпляры. Для некоторых типов это имеет значение. Экземпляр Show для [a] зависит от типа a, даже если список пуст. Проверьте результат show ([] :: [Char]) против результата show ([] :: [Int]).

Но все это как бы в стороне. Дело в том, что типы определяются во время компиляции, а значения определяются во время выполнения. Вы представили ситуацию, для которой переменные типа не имеют значения только для некоторых входных значений. В этом случае переменные типа по-прежнему имеют значение, поскольку они управляют поведением в других случаях.

Вам придется правильно разрешать неоднозначные типы, потому что именно так ghc знает, какой код использовать. Есть несколько способов сделать это удобно, например, использование расширения ScopedTypeVariables, но его трудно рекомендовать, не имея более представительного фрагмента кода. Самая важная вещь, которую я могу сказать, это то, что это действительно имеет значение, потому что выбор экземпляра выполняется во время компиляции, задолго до того, как значение будет когда-либо замечено.

...