2015-05-05 3 views
3

Я сделал функцию в haskell, которая должна взять список вместе с размером списка; и предполагается создать Data.Vector.Mutable.MVector с заданным размером, заполнить вектор содержимым списка и вернуть этот вектор.Подписи типа Haskell и Monads

TL; DR

  • Я хочу знать, почему тип подписи я поставляется не работает. Что мне не хватает в этом, что делает его неприемлемым как подпись типа?
  • Возможно ли создать функцию, выполняющую то, что я указал выше, при использовании моей подписи типа?
  • Как интерпретировать подпись типа, сгенерированную компилятором, на основе кода, который я написал?

Это функция:

vecFromList lst sz = MV.new sz >>= (\vec -> fillV (zip [0..sz - 1] lst) vec) where 
    fillV [] vec = vec 
    fillV ((i, v):xs) vec = MV.write vec i v >> fillV xs vec 

Большинство из них я написал на самом деле не пытаясь понять, что они делают (последняя строка) и, как следствие, я не могу придумать с подходящей подписью типа. Однако компилятор вмешалась, чтобы сохранить день с этим:

компилятором сигнатуру

vecFromList 
    :: (PrimMonad (MVector t), PrimState (MVector t) ~ t) => 
    [b] -> Int -> MVector t b 

Я слышал, кто-то сказал Wat? О, только я, в любом случае ... Прежде чем я пытался компилировать его, это тип подписи я думал, что должно работать:

Один я думал, что должен работать

vecFromList :: PrimMonad m => [t] -> Int -> MV.MVector (PrimState m) t 

Это должно быть очевидно, к этому моменту, что эта несколько упрощенно выглядящая сигнатура типа, которая, похоже, выглядит точно так же, как то, что я хочу, чтобы функция выполняла, на самом деле не работы. Чтобы придумать типа подписи, я использовал подпись типа некоторых других функций в векторном модуле, что я думал, были похожи на него, как этот, например:

Data.Vector.Mutable.read 
    :: PrimMonad m => MVector (PrimState m) a -> Int -> m a 

Теперь я по-прежнему относительно новый для haskell, поэтому я все еще пытаюсь привыкнуть к символам и знакам, используемым на этом языке, и особенно близко к пониманию, почему то, что кажется простым заданием, должно стать таким запутанным из-за Monands. Например, какова цель MVector, имеющая такой вид MVector :: * -> * -> *: ??

ответ

5

Вы почти у цели. Вы ожидали типа подпись является правильной, за исключением результирующих MVector потребности быть в монаде m:

vecFromList :: PrimMonad m => [t] -> Int -> m (MV.MVector (PrimState m) t) 

fillV функция должна иметь тип

fillV :: [(Int, t)] 
      -> MV.MVector (PrimState m) t -> m (MV.MVector (PrimState m) t) 

но вы [] случая дает вектор без return Ввод в m.Вот рабочая версия:

vecFromList :: PrimMonad m => [t] -> Int -> m (MV.MVector (PrimState m) t) 
vecFromList lst sz = MV.new sz >>= (\vec -> fillV (zip [0..sz - 1] lst) vec) where 
    fillV [] vec   = return vec 
    fillV ((i, v):xs) vec = MV.write vec i v >> fillV xs vec 

и рабочий пример:

> V.create $ vecFromList [1,2,3] 3 
fromList [1,2,3] 

Обратите внимание, что вы на самом деле не изменить vec в вашей fillV функции, вы только ссылку на него, вы можете использовать for_ функцию из Data.Foldable вместо явного написания цикла. Я обычно пишу изменяемый вектор кода в do блоков, потому что он делает вещи яснее для меня:

vecFromList2 :: PrimMonad m => [t] -> Int -> m (MV.MVector (PrimState m) t) 
vecFromList2 l n = do 
    v <- MV.new n 
    for_ (zip [0..n - 1] l) $ \(i,a) -> MV.write v i a 
    return v 

К сожалению, работа с изменяемыми векторами в Haskell может получить сложно, и это требует практики. Использование TypedHoles и PartialTypeSignatures может помочь.

Причина: MVector имеет PrimState m, поэтому он может работать с ST или IO. Вы можете найти объяснение этого here.

+0

Возможно, вы имели в виду 'forM_', а не' for_'? Спасибо – smac89

+0

@ Smac89 ['for_'] (https://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Foldable.html#v:for_) и [' forM_'] (https://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Foldable.html#v:forM_) по существу то же самое, 'for_' просто имеет более слабое (' Аппликативное') ограничение. – cchalmers

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