2012-02-08 2 views
0

С нижеприведенным фрагментом я хочу добавить/добавить строку в список, который является частью значения, хранящегося на карте.Ошибка объявления типа: [Char] и [[Char]]

Из фрагмента кода ниже я получаю ошибку

Couldn't match expected type `Char' with actual type `[Char]' 
    Expected type: Map.Map ([Char], Integer) [Char] 
     Actual type: Map.Map ([Char], Integer) [[Char]] 

и я не совсем уверен, что это должен сказать мне. Может ли это быть разрешено с изменением кода или должно быть что-то вроде

{-# LANGUAGE OverloadedStrings #-} 
{-# LANGUAGE FlexibleInstances #-} 

Вместе с заявлением на экземпляр?

import Data.Time 
import Data.Time.Clock.POSIX 
import qualified Data.PSQueue as PSQ 
import qualified Data.Map as Map 
import Data.Maybe 
import Control.Category 
import Control.Concurrent 
import Control.Concurrent.MVar 
import Control.Monad 

key = ("192.168.1.1", 4711) 
messages = ["aaa", "bbbb", "ccccc"] 

newRq = do 
     time <- getPOSIXTime 
     let q = PSQ.singleton key time 
     let m = Map.singleton key messages 
     return (q, m) 

appendMsg :: String -> (String, Integer) -> Map.Map ([Char], Integer) [Char] -> Map.Map ([Char], Integer) [Char] 
appendMsg a (b, c) m = m2 
     where 
      f x = x ++ a 
      m2 = Map.adjust f (b, c) m 

main :: IO() 
main = do 
    (q, m) <- newRq 
    let m2 = appendMsg "first" key m 
    print (m2) 

ответ

2

Вам необходимо изменить код. Вы начинаете с Map (String, Integer) [String], создавая синглтон со значением messages. Однако функция обновления написана для Map (String, Integer) String. Либо изменить его к соответствующему типу, сделав его f x = x ++ [a] (и изменить тип подписи

appendMsg :: String -> (String, Integer) -> Map (String, Integer) [String] 
             -> Map (String, Integer) [String] 

тоже) или изменить начальную карту, используя, например, unwords messages. (Я думаю, вам лучше захотеть первый.)

+0

Пробовал это уже. Однако, я получаю сообщение об ошибке «Нет экземпляра для (IsString Char) , возникающего из буквенного' 'ccccc''. Добавление 'import Data.String' тоже не помогает. –

+0

Вспомните, что вы должны изменить объявление типа 'appendMsg' для использования' Map (String, Integer) [String] '. –

+0

Спасибо! Есть, кстати, [String] не [Char]? –

1

Карта, которую вы создаете с Map.singleton key messages, является Map.Map (String, Integer) [String]. Однако ваша декларация appendMsg указывает, что вы действительно хотите Map.Map (String, Integer) String. Вам нужно пересмотреть свой newRq и выяснить, что вы действительно пытаетесь сделать с этой линией Map.singleton.

2

[Char] и String одного типа. Прелюдия Haskell имеет следующее определение типа синоним:

type String = [Char] 

... которые в основном означает, что эти два типа означают одно и то же и полностью взаимозаменяемы. Это означает, что мы можем переписать ошибку компилятора, как:

Expected type: Map (String, Integer) String 
    Actual type: Map (String, Integer) [String] 

два параметра типа по Map типа его Key типа и его Value типа. Поэтому, если у вас есть тип Map Int String, это означает, что это карта с Int s в качестве ключей и Strings в качестве значений. Это означает, что теперь вы можете интерпретировать сообщение компилятора немного более ясно:

Expected type: Map from keys of type "(String, Integer)" to values of type "String" 
    Actual type: Map from keys of type "(String, Integer)" to values of type "[String]" 

Это говорит нам о том, что где-то в вашем коде вы дали ему карту, где каждое значение является [String] (т.е. список строк), но он ожидал карту, где каждое значение было всего лишь одним String. На самом деле, вы можете проследить ошибку на эту строку кода:

let m = Map.singleton key messages 

messages это, как вы уже догадались, списка из String с (т.е. [String]), и вы сказали ей, чтобы сохранить весь массив messages как один элемент на карте m, когда вы использовали функцию singleton для ее инициализации. Итак, Haskell правильно вывел тип значения m должен был быть [String] (что явно не то, что вы намеревались).

Составитель тогда заметил что-то неладное, когда вы пытались добавить строку к каждому элементу в вашей карте в следующей строке:

let m2 = appendMsg "first" key m 

Вы сказали компилятору «Пожалуйста конкатенировать эту строку на каждый элемент моего map ", а компилятор затем сообщает вам:« Но у вас нет нескольких строк, хранящихся на вашей карте, у вас есть только один список строк, сохраненный как одно значение на вашей карте, поэтому я не могу добавить «первый» в массив сам".

Исправления просто, где вместо того, чтобы использовать singleton для инициализации m, вы просто fromList, который принимает список элементов (т.е. messages) и преобразует каждый элемент в списке на элемент карты, который является то, что вы хотели ,

+0

"(т. Е. Массив строк)", я полагаю, вы знаете разницу и просто немного отвратительны, но важно сохранить разницу между списками и массивами, чтобы не путать новичков. Попытка рассматривать списки как массивы - распространенная ошибка, ведущая к разочарованию. –

+0

Да, я хотел сказать список. –

Смежные вопросы